web-dev-qa-db-fra.com

Définissez les fichiers de contenu sur "Copier local: toujours" dans un package de nuget

Je génère un paquet de nuget à partir d'un projet avec cette commande dans l'événement post-build. la variable %conf% est définie sur la bonne configuration (débogage ou édition) et %1 est le nom du projet (par exemple, "MyCompany.MyProject").

nuget pack -Prop Configuration=%conf% "%1.csproj" -exclude *.sql -IncludeReferencedProjects

Ce paquet est pour notre propre usage seulement, il ne sera jamais publié sur Nuget. Il se termine dans notre référentiel privé.

Dans le projet, un fichier est défini sur generate action : content et copy local : always. (Mon studio visuel est en français, je ne suis donc pas sûr à 100% de la traduction). Appelons-le importantfile.xml.

Dans le paquet généré, je me retrouve avec cette structure:

- content
    - importantfile.xml
- lib
    -net45 (.NetFramework,Version=v4.5)
        -MyCompany.MyProject.dll

Ce qui est bien, je veux que importantfile.xml soit déployé dans le package, car, eh bien, ce fichier est important!

Lorsque j'installe le package dans un autre projet, importantfile.xml est déployé à la racine du projet. C'est bon. Mais il n'est pas défini sur copy local : always.

J'ai besoin de importantfile.xml pour être copy local : always dans ce projet où j'installe mon paquet.

Comment puis-je y parvenir?

Notes:

Je peut mettre copy local : always sur le fichier juste après l'installation du paquet, ce n'est pas grave. Je vivrais avec si les mises à jour ultérieures du paquet laissaient cette propriété telle quelle, ce qui n'est pas le cas. Lors de la mise à jour du paquet, copy local est réinitialisé sur never (comme indiqué ici ).

Il y a un fichier nuspec dans le dossier du projet, le voici:

<?xml version="1.0"?>
<package >
  <metadata>
    <id>$id$</id>
    <version>$version$</version>
    <title>$title$</title>
    <authors>$author$</authors>
    <owners>$author$</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>$description$</description>
    <copyright>Copyright 2014</copyright>
    <tags>some random tags</tags>
  </metadata>
</package>
56
Johnny5

Vous pouvez utiliser PowerShell et le hook Install.ps1 fourni par NuGet.

Voir la documentation .

Via PowerShell, vous devez "rechercher" l'élément de contenu qui inclut votre importantfile.xml dans un attribut. Lorsque le script l'a trouvé, il doit ajouter <CopyToOutputDirectory>Always</CopyToOutputDirectory> en tant qu'élément enfant.

    <Content Include="importantfile.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>

Vous pouvez trouver des extraits de PowerShell ici . Jetez un coup d’œil aux fichiers .ps1.

Vous pouvez essayer ce qui suit (non testé). Le fichier doit être nommé Install.ps1 et copié dans le dossier tools:

param($installPath, $toolsPath, $package, $project)

# Load project XML.
$doc = New-Object System.Xml.XmlDocument
$doc.Load($project.FullName)
$namespace = 'http://schemas.Microsoft.com/developer/msbuild/2003'

# Find the node containing the file. The tag "Content" may be replace by "None" depending of the case, check your .csproj file.
$xmlNode = Select-Xml "//msb:Project/msb:ItemGroup/msb:Content[@Include='importantfile.xml']" $doc -Namespace @{msb = $namespace}


#check if the node exists.
if($xmlNode -ne $null)
{
    $nodeName = "CopyToOutputDirectory"

    #Check if the property already exists, just in case.
    $property = $xmlNode.Node.SelectSingleNode($nodeName)
    if($property -eq $null)
    {
        $property = $doc.CreateElement($nodeName, $namespace)
        $property.AppendChild($doc.CreateTextNode("Always"))
        $xmlNode.Node.AppendChild($property)

        # Save changes.
        $doc.Save($project.FullName)
    }
}

Vous devez également vérifier si tout est complètement supprimé lors de la désinstallation du paquet.

Note de Jonhhy5

Lors de la mise à jour du package via update-package, Visual Studio avertit que le projet est modifié "en dehors de l'environnement". Cela est causé par $doc.Save($project.FullName). Si je clique sur recharger avant la commande est complètement terminée, des erreurs sont parfois générées. L'astuce consiste à laisser la boîte de dialogue jusqu'à la fin du processus et à alors recharger les projets.

3
timmkrause

Au lieu d'utiliser un script PowerShell, une autre approche consiste à utiliser un fichier cible/props MSBuild portant le même nom que l'ID de package:

<Project xmlns="http://schemas.Microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <None Include="$(MSBuildThisFileDirectory)importantfile.xml">
      <Link>importantfile.xml</Link>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>

Dans le fichier nuspec, au lieu d’ajouter les fichiers requis au répertoire Content, ajoutez-les au répertoire Build avec le fichier cibles.

  • Construire
    • importantfile.xml
    • MyPackage.targets
  • lib
    • net45
      • MyAssembly.dll

Si vous avez besoin d'un contenu différent pour différentes architectures, vous pouvez ajouter des dossiers d'architecture sous Build, chacun avec son propre fichier de cibles.

Avantages de l’utilisation d’un fichier de cibles sur le script PowerShell avec le répertoire NuGet Content:

  • les fichiers de contenu requis ne sont pas affichés dans le projet dans Visual Studio.
  • les fichiers de contenu sont liés à plutôt que copiés dans le répertoire de chaque projet qui fait référence au package NuGet (empêchant la multiplication des copies et conservant le même comportement que pour les assemblées/bibliothèques des packages NuGet) 
  • Les scripts PowerShell fonctionnent uniquement dans Visual Studio et ne sont pas exécutés lorsque NuGet est exécuté à partir de la ligne de commande (serveurs de génération, autres IDE et autres systèmes d'exploitation), cette approche fonctionnera partout
  • Les scripts d'installation de PowerShell ne sont non pris en charge dans le système NuGet 3.x project.json .
127
kjbartel

Je sais que vous avez une solution qui fonctionne, mais cela ne fonctionne pas pour moi. Je vais donc partager ce que j'ai extrait du paquet NLog.config NuGet install.ps1 (source de github ici ).

NOTE: ce n'est pas mon code, c'est le contenu du fichier install.ps1 de le paquet NLog.config nuget partage simplement les connaissances.

Cela me semble un peu plus simple et j'espère juste aider les autres qui risquent de tomber sur cela.

Vous pouvez trouver les valeurs int acceptées pour BuildAction ici et les valeurs acceptées pour CopyToOutputDirectory here .

si le lien se rompt à nouveau  enter image description here

Champs PrjBuildActionCompile 1
Le fichier est compilé.

prjBuildActionContent 2
Le fichier est inclus dans le groupe de sortie du projet Contenu (voir Déploiement d'applications, de services et de composants).

prjBuildActionEmbeddedResource 3
Le fichier est inclus dans l’Assemblée générée principale ou dans une Assemblée satellite en tant que ressource.

prjBuildActionNone 0
Aucune action n'est entreprise.

param($installPath, $toolsPath, $package, $project)

$configItem = $project.ProjectItems.Item("NLog.config")

# set 'Copy To Output Directory' to 'Copy if newer'
$copyToOutput = $configItem.Properties.Item("CopyToOutputDirectory")

# Copy Always Always copyToOutput.Value = 1
# Copy if Newer copyToOutput.Value = 2  
$copyToOutput.Value = 2

# set 'Build Action' to 'Content'
$buildAction = $configItem.Properties.Item("BuildAction")
$buildAction.Value = 2
37
workabyte

J'ai fait ceci qui copie les fichiers de mon dossier de construction dans le dossier de sortie (bin/debug ou bin/release). Fonctionne comme un charme pour moi.

Fichier Nuspec:

<package>
  <files>
    <file src="\bin\Release\*.dll" target="lib" />
    <file src="\bin\Release\x64\*.dll" target="build\x64" />
    <file src="\bin\Release\x86\*.dll" target="build\x86" />
    <file src="MyProject.targets" target="build\" />    
  </files>
</package>

MyProject.targets

<Project xmlns="http://schemas.Microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <NativeLibs Include="$(MSBuildThisFileDirectory)**\*.dll" />
    <None Include="@(NativeLibs)">
      <Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>
5
Rahbek

J'ai écrit un petit outil appelé NuGetLib pour ajouter automatiquement des fichiers au paquet Nuget après la construction.

  1. créer un dossier tools avec votre script Install.ps1
  2. construisez votre nugetPackage
  3. ajouter le dossier outils à la nugetPackage construite

https://stackoverflow.com/a/47134733/6229375

0
Dominic Jonas