Skip to content

Developing with locally modified nuget packages

Mark Kidder edited this page Oct 17, 2023 · 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, but excluding significantly higher versions such as 8.0.1-alpha0001)
    • To update quickly after building packages
      • right-click your solution in Visual Studio
      • choose "Manage NuGet Packages for Solution..."
      • go to the Updates tab
      • select the checkbox to select all packages and click Update
    • Alternatively, choose a branch name that gitversion.yml doesn't map to an alpha version
  • Optional: Create a Visual Studio External Tool (Tools > External Tools...) to pack and publish your packages
    Title: Pac&k NuGet Packages
    Command: C:\Program Files\Microsoft Visual Studio\2022\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:
  • Do one of the following:
    • Bump the version. This article describes what is considered "newer". Libpalaso uses GitVersion, so each new commit bumps the version.
    • Clear the cache: Delete the packages to be replaced from %USERPROFILE%\.nuget\packages\ or $HOME/.nuget/packages (Note: For Fieldworks development you will also need to delete the packages from fwrepo\fw\packages)
  • 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/