Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extract NuGet contentFiles to a specific directory?

Tags:

nuget

msbuild

What I've tried so far:

I've got the following .nuspec file, defining my package (simplified for better readability):

<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
  <metadata>
  .
  .
  .
    <dependencies/>
    <contentFiles>     
      <files include="any\any\config\*.*" buildAction="None" copyToOutput="true" flatten="false"/>
    </contentFiles>
  </metadata>
  <files>
    <file src="bin\Assembly.dll" target="lib\net461" />
    <file src="bin\Assembly.pdb" target="lib\net461" />
    <file src="Config\cf.xml" target="contentFiles\any\any\config"/>
    <file src="Config\cf.txt" target="contentFiles\any\any\config"/>
  </files>
</package>

As you can see, it contains a compiled Assembly along with it's debug symbols file as well as two content Files in a sub directory.

This results in the following compilation output, where the Assembly.dll is extracted to the output directory as well as the config sub directory (with the two cf.* files in it):

actual build output


Question:

What I want to do is to move the sub directory config one step up in the directory tree, so it sits next to the output directory - basically maintaining the structure of the file input in the .nuspec file (assuming bin is the output directory of my .csproj):

nuspec directory structure desired build output

How can I tell the NuGet package the exact location where I want the contentFiles to be extracted to?

like image 717
M463 Avatar asked Nov 07 '22 15:11

M463


1 Answers

You can achieve this by creating a MSBuild target that moves your config folder one level above the project build output.

Add a .targets file with the following content to your NuGet's build\net461 folder:

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!-- Sets up items for target MoveConfigFiles, so that they can be used as Inputs and Outputs. -->
  <Target Name="PrepareMoveConfigFiles" AfterTargets="Build">
    <!-- ItemGroup wrapped in Target to delay evaluation of contained Items -->
    <ItemGroup>
      <!-- Contains source locations of files to be moved -->
      <ConfigSourceFiles Include="$(OutputPath)\config\**\*.*" />
      <!-- Contains target locations of files to be moved -->
      <ConfigTargetFiles Include="@(ConfigSourceFiles->'%(FullPath)'->Replace('\config\', '\..\config\'))" />
    </ItemGroup>
  </Target>

  <!-- Moves files from $(OutputPath)\config to $(OutputPath)\..\config,
       then deletes $(OutputPath)\config. -->
  <Target Name="MoveConfigFiles" AfterTargets="PrepareMoveConfigAndSqlFiles" Inputs="@(ConfigSourceFiles)" Outputs="@(ConfigTargetFiles)">
    <Move SourceFiles="@(ConfigSourceFiles)" DestinationFiles="@(ConfigTargetFiles)" />
    <RemoveDir Directories="$(OutputPath)\config" />
  </Target>
</Project>

The target PrepareMoveConfigFiles is executed after the Build target (which guarantees the NuGet's contents exist in build output), and sets up items used as Inputs and Outputs of the next MoveConfigFiles target. (The items are set inside this target to ensure they are evaluated after the Build target has completed. If the item definitions would be placed below the Project level, they would be evaluated earlier and thus would potentially be empty because the files of the content folder have not yet been deployed.)

The ConfigSourceFiles item just contains the source files, and ConfigTargetFiles takes the paths of all ConfigSourceFiles and replaces \config\ with \..\config\, which leads to the desired target locations.

The MoveConfigFiles target then uses the Move and RemoveDir tasks to accomplish the movement of files and deletion of the original config folder.

like image 67
Christian Avatar answered Nov 30 '22 21:11

Christian