Skip to content

Developing with locally modified nuget packages

papeh edited this page Oct 29, 2021 · 16 revisions

Working in a project that uses libraries that come as nuget packages requires a slightly different approach when it comes to debugging and making changes in a library that the project depends on.

This document shows different ways how this can be done.

...

Methods to use local changes

  1. Copy library to output directory. Disadvantage: gets overwritten when rebuilding client project
  2. Replace library files in the nuget package by copying library to packages/nuget.package.name.version/ (for old-style projects) or $HOME/.nuget/packages/nuget.package.name/version/ (for sdk-style projects). (Note: when done debugging, the package can be deleted so that rebuilding will restore it to its original condition.)
  3. Locally commit the library changes and create a nuget package. Copy that to a local directory that you add as additional nuget source. Then update the nuget package version that the client project uses. If you commit the library changes to the master branch you'll get the same version number that the nuget package will have later on (if the GitHub PR gets rebased)
  4. Some nuget packages may allow specifying a custom path to the assemblies (eg SIL.ReleaseTasks)
  5. (Untested but promising) Override PackageReference'd dll with Reference to your local dll https://docs.microsoft.com/en-us/nuget/reference/msbuild-targets#replacing-one-library-from-a-restore-graph

Examples

1. Using locally-built SIL.ReleaseTasks.dll with flexbridge by copying:

(Note that dotnet may be too rigorous with project dependencies for this to work, but it does work with just msbuild 16.6.0 in mono 6.12.0.90.)

Find where flexbridge already has SIL.ReleaseTasks.dll:

flexbridge$ find -name SIL.ReleaseTasks.dll
./packages/SIL.ReleaseTasks/tools/net461/SIL.ReleaseTasks.dll
./packages/SIL.ReleaseTasks/tools/netstandard2.0/SIL.ReleaseTasks.dll

Find where SIL.BuildTasks places SIL.ReleaseTasks.dll:

SIL.BuildTasks$ find -name SIL.ReleaseTasks.dll
...
./output/Release/net461/SIL.ReleaseTasks.dll
...

Copy the locally-built assembly over the assembly from nuget:

flexbridge$ cp ~/projects/SIL.BuildTasks/output/Release/net461/SIL.ReleaseTasks.dll packages/SIL.ReleaseTasks/tools/net461/SIL.ReleaseTasks.dll

3. Publish the nuget packages locally

Setup:
  • Set up a local NuGet repository
  • Set an enviroment variable LOCAL_NUGET_REPO with the path to a folder on your computer (or local network) to publish locally-built packages
  • Add the following target to Directory.Build.targets in the same folder as the project or solution; this will publish your packages whenever they are packed (this target is already included in libpalaso source)
  <Target Name="CopyPackage" AfterTargets="Pack" Condition="'$(LOCAL_NUGET_REPO)'!='' AND '$(IsPackable)'=='true'">
    <Copy SourceFiles="$(PackageOutputPath)/$(PackageId).$(PackageVersion).nupkg"
      DestinationFolder="$(LOCAL_NUGET_REPO)"/>
  </Target>
  • Set client PackageReferences to have Version="8.0.0-*" (-* selects the latest version, including prerelease)
  • Optional: Create a Visual Studio External Tool (Tools > External Tools...) to pack and publish your packages Title: Pack NuGet &Packages Command: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe Arguments: /t:pack Initial directory: $(SolutionDir)
For even the smallest tweak, the following steps need to be followed in order:
  • Bump the version. This article describes what is considered "newer". Libpalaso uses GitVersion, so each new commit bumps the version. To avoid having to bump the version, clean $HOME/.nuget/packages each time the package is built
  • Build and pack and publish (msbuild /t:pack or in Visual Studio choose Tools > Pack NuGet Packages)
  • Rebuild the client code
  • In some cases, it may be necessary to restart Visual Studio or even your computer (usually only if this is the first time to publish the package locally) before Visual Studio recognises the new version exists

4. Using locally-built SIL.ReleaseTasks.dll with flexbridge via variable:

SIL.ReleaseTasks looks for a SilReleaseTasksPath property to find its assembly, as seen in SIL.BuildTasks/SIL.ReleaseTasks/SIL.ReleaseTasks.props:

  <SilReleaseTasksPath Condition="$(SilReleaseTasksPath) == '' And '$(MSBuildRuntimeType)' != 'Core'"
    >$(MSBuildThisFileDirectory)..\tools\net461</SilReleaseTasksPath>
  ...
  <UsingTask TaskName="CreateChangelogEntry" AssemblyFile="$(SilReleaseTasksPath)/SIL.ReleaseTasks.dll" />

Flexbridge can import this .props file in FLExBridge.proj:

<Import Project="$(RootDir)/packages/SIL.ReleaseTasks/build/SIL.ReleaseTasks.props"
 Condition="Exists('$(RootDir)/packages/SIL.ReleaseTasks/build/SIL.ReleaseTasks.props')" />

Build SIL.ReleaseTasks (in SIL.BuildTasks):

SIL.BuildTasks$ msbuild build/SIL.BuildTasks.proj

Use the locally SIL.ReleaseTasks.dll assembly with Flexbridge:

flexbridge$ msbuild build/FLExBridge.proj /t:PreparePublishingArtifacts /p:UploadFolder=Stable \
            /p:SilReleaseTasksPath=${HOME}/projects/SIL.BuildTasks/output/Release/net461/