Copier dans le répertoire de sortie copie la structure des dossiers mais ne souhaite copier que les fichiers

87

J'ai un VS2008 Je souhaite copier certains fichiers d'un répertoire dans mon /bin/dossier. J'ai défini les fichiers (situés dans /common/browserhawk/) sur "Copier dans le répertoire de sortie". Cependant, il copie également la structure des dossiers: les fichiers sont copiés dans/bin/common/browserhawk/

Comment faire pour copier ces fichiers uniquement /bin/? Je ne souhaite pas les stocker à la racine du site Web pour les copier correctement.

Question connexe: Visual Studio ajoute .dll et .pdb au projet après la compilation

Steve Wright
la source

Réponses:

59

Vous pouvez ajouter un événement de post-construction pour copier les fichiers.
Accédez aux propriétés du projet, onglet Événements de construction et ajoutez ce qui suit à la ligne de commande de l'événement post-construction:

copy "$(ProjectDir)\common\browserhawk\*.*" "$(TargetDir)"

N'oubliez pas d'inclure les guillemets si le chemin de votre projet contient des espaces.

Bill A.
la source
Merci pour ce conseil, car cela vient de fonctionner pour moi dans VS2012 également.
Dib
2
J'ai légèrement modifié ceci dans mon cas:xcopy /s /d /y "$(ProjectDir)\stuff" "$(TargetDir)\stuff"
Danny Staple
44

Comme je ne peux pas commenter les réponses précédentes, je vais mettre la solution ici:

En ajoutant à ce que @PaulAlexander a fourni, ajoutez ce qui suit à votre fichier .csproj / .vbproj:

<ItemGroup>
    <AvailableItemName Include="RootContent">
      <Visible>false</Visible>
    </AvailableItemName>  
</ItemGroup>
<Target Name="AfterBuild">
    <Copy
        DestinationFolder="$(OutputPath)"
        SourceFiles="@(RootContent)"
        SkipUnchangedFiles="true"
        />  
</Target>

Cela vous permet de sélectionner "RootContent" comme action de construction dans la fenêtre Propriétés, et tout est accessible via l'interface graphique. Une explication plus complète: l'option "AvailableItemName" crée essentiellement une nouvelle liste nommée à laquelle vous pouvez affecter des éléments du projet sous la propriété "Build Action" de la fenêtre Propriétés. Vous pouvez ensuite utiliser cette liste nouvellement créée dans n'importe quelle cible de votre choix (par exemple via "@ (RootContent)").

onde de choc
la source
Belle réponse, je viens de l'utiliser moi-même pour réussir!
Chris Marisic
Notez également que VS 2010 (pas sûr des anciennes versions) se plaindra d' AvailableItemNameêtre un élément non valide si vous éditez le fichier de projet dans VS; ignorez simplement l'avertissement, cela fonctionne de toute façon.
Aaronaught
2
Malheureusement, cela ne copie le fichier que dans le répertoire de sortie du projet auquel appartient le fichier - et non dans le répertoire de sortie du projet de démarrage. Ceci est important lors de son utilisation dans un projet de bibliothèque.
Sebastian Krysmanski
2
Cela fonctionne très bien pour la construction en mode version et débogage avec vs2008, mais cela ne semble pas fonctionner lors de l'utilisation de la publication en un clic. Aucune suggestion?
Soenhay
2
Cela n'a pas fonctionné pour moi en vs2015. Corrigé en réécrivant un peu la cible: <Target Name="RootOutputCopyTarget" AfterTargets="Build">... </Target>
lorond
44

Si vous modifiez le .csproj / .vbproj dans un éditeur de texte, vous pouvez contrôler l'emplacement du fichier dans le répertoire de sortie, ainsi que le nom du fichier dans le répertoire de sortie. Par exemple:

<None Include="content\someContent.txt">
  <Link>someContentInOutputDirectory.txt</Link>
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

Cela mettra le fichier content\someContent.txtdans bin\someContentInOutputDirectory.txt. Vous pouvez également choisir un sous-répertoire dans binsi vous le souhaitez; ajoutez-le simplement à l'élément Link.

Daniel Yankowsky
la source
3
Wow, j'ai eu la chance d'en avoir besoin maintenant et pas il y a deux jours. Merci; c'est bien!
Asherah
2
Oh mon dieu, merci. Je viens de passer 6 heures à essayer de réparer certaines ordures du coin où VS ne copiait pas les fichiers .dll de manière intelligente. C'est la vraie réponse à la vie, à l'univers et à tout.
Brandon
5
C'est de loin la meilleure solution
PhilHdt
1
J'ai découvert qu'une fois que j'avais fait cela et rechargé le projet dans Visual Studio, les fichiers de dépendance avaient disparu de l'explorateur de solutions comme s'ils n'étaient pas inclus dans le projet. Cependant, il se construit toujours comme prévu et se copie dans la sortie comme souhaité. Pour contourner le problème, j'ajoute actuellement chaque fichier deux fois; une fois sans action, et une fois avec le jeu «copier dans la sortie».
Éliette
1
Ce n'est pas l'usage prévu de cette balise. Dans VS2013, cela émet un avertissement lors du chargement du projet et le fichier n'est pas visible comme ajouté au projet car il s'agit du répertoire du projet.
jpmc26
15

Je pense que la commande XCOPY gère mieux les répertoires et les fichiers. Par conséquent,

    XCOPY "$(ProjectDir)common/browserhawk" "$(TargetDir)" /E /I /F /Y

Ce qui permet de créer des dossiers hors du répertoire cible.

    XCOPY "$(ProjectDir)Templates" "$(TargetDir)" /E /I /F /Y

La structure des dossiers / fichiers du projet de:

    A:\TEMP\CONSOLEAPPLICATION3\TEMPLATES
    ├───NewFolder1
    ├───NewFolder2
    │       TextFile1.txt
    │       TextFile2.txt
    └───NewFolder3
            TextFile1.txt
            TextFile2.txt
            TextFile3.txt

Devient:

    A:\TEMP\CONSOLEAPPLICATION3\BIN\DEBUG
    │   ConsoleApplication3.exe
    │   ConsoleApplication3.pdb
    │   ConsoleApplication3.vshost.exe
    │   ConsoleApplication3.vshost.exe.manifest
    ├───NewFolder1
    ├───NewFolder2
    │       TextFile1.txt
    │       TextFile2.txt
    │
    └───NewFolder3
            TextFile1.txt
            TextFile2.txt
            TextFile3.txt
AMissico
la source
/Dpeut également être utile pour éviter d'écraser d'éventuelles modifications.
KurzedMetal
10

Ajoutez ce qui suit à votre fichier .csproj / .vbproj

<Target Name="AfterBuild">
    <Copy
        DestinationFolder="$(OutputPath)"
        SourceFiles="@(RootContent)"
        SkipUnchangedFiles="true"
        />  
</Target>

Modifiez ensuite l'action de génération de tous les fichiers de votre choix dans le dossier racine en RootContent.

Paul Alexander
la source
Pas par les boîtes de dialogue ... mais vous pouvez éditer votre projet dans VS. Cliquez avec le bouton droit sur le projet et sélectionnez Décharger le projet. Cliquez ensuite avec le bouton droit de la souris et sélectionnez Modifier. Ensuite, vous pouvez modifier le fichier MSBuild qui est votre projet.
Paul Alexander
2
Merci, cela semble utile. Malheureusement, même après avoir ajouté votre extrait de code au fichier .vbproj, RootContentn'apparaît pas dans la liste déroulante «Action de génération» et la saisie manuelle entraîne une erreur «La valeur de propriété n'est pas valide» de Visual Studio. Qu'est-ce que j'ai raté?
Heinzi
Ne fonctionne pas avec le projet d'application console Visual Studio 2010 C #.
AMissico
Ne fonctionne pas avec le projet d'application console Visual Studio 2010 VB.NET.
AMissico le
Ne fonctionne pas avec le projet d'application console Visual Studio 2008 C #.
AMissico le
5

Je l'ai utilisé dans VS2010, VS2015, VS2017 et VS2019. Je préfère cette solution car:

  1. Le XML est réutilisable dans n'importe quel projet
  2. Le "RootContent" est choisi comme action de génération dans l'interface utilisateur de Visual Studio, comme tout autre "contenu"
  3. Le "CopyToOutputDirectory" est respecté, comme vous vous en doutez
  4. Le RootContent est ajouté à la sortie du projet: passe par Project-References, obéit à "Clean", etc.
  5. Le RootContent peut être spécifié avec un caractère générique, en préservant la structure de dossier récursive:
<RootContent Include="common\browserhawk\**">
  <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</RootContent>

Vers le début du fichier de projet:

  <ItemGroup>
    <AvailableItemName Include="RootContent">
      <!-- Add "RootContent" as a choice in the "Build Action" dropdown. -->
      <Visible>True</Visible>
    </AvailableItemName>
  </ItemGroup>

Emprunté à cette réponse

Après l'importation Microsoft .targets:

  <PropertyGroup>
    <AssignTargetPathsDependsOn>
      $(AssignTargetPathsDependsOn);
      IncludeRootContentAsContent;
    </AssignTargetPathsDependsOn>
  </PropertyGroup>
  <Target Name="IncludeRootContentAsContent">
    <CreateItem Include="@(RootContent)" AdditionalMetadata="TargetPath=%(RecursiveDir)%(Filename)%(Extension)">
      <Output ItemName="ContentWithTargetPath" TaskParameter="Include" />
    </CreateItem>
  </Target>

Emprunté à cette réponse

MattGerg
la source
C'est bien - j'échangerais ce RootContentqui implique «codé en dur» pour CustomContentindiquer qu'il s'agit d'un contenu spécialisé que nous ajoutons à ce projet et que nous devons copier de cette manière particulière. De plus, j'avais besoin TargetPath=%(RecursiveDir)%(Filename)%(Extension)de recréer la structure des CustomContentdossiers à partir des fichiers spécifiés vers le chemin de sortie.
Jonno
@Jonno Le but est de copier le (s) fichier (s) directement dans le répertoire de sortie racine, quel que soit RecursiveDirectory. L'action de construction intégrée "Content" nous fournit déjà un mécanisme pour copier tout en conservant le RecursiveDirectory.
MattGerg
Je n'ai pas eu l'occasion de tester cela depuis un certain temps, mais la configuration de l'action de génération "Contenu" ne provoquerait-elle /common/browserhawk/pas la copie des fichiers sous /bin/common/browserhawk/comme le dit l'OP? IIRC, mon intention était d'avoir /common/browserhawk/a.txtfini dans /bin/a.txtmais autoriser la récursion à partir de là vers le bas, donc /common/browserhawk/secret/stuff.pngfinit dans /bin/secret/stuff.png.
Jonno le
@Jonno Ok, ouais, ça a du sens maintenant. J'ai mis à jour la réponse pour inclure le %(RecursiveDirectory). C'est vraiment cool, car en plus de sélectionner des fichiers individuels dans l'EDI, vous pouvez également spécifier plusieurs fichiers avec des caractères génériques. Lorsque vous utilisez le **caractère générique, toute la structure du dossier sera préservée.
MattGerg
1
Merci beaucoup pour une si bonne réponse! Je pense que cette réponse est la bonne pour les raisons suivantes: 1. Pas de cmds externe 2. plateforme croisée
George Anisimov
2

J'ai fini par ajouter une étape au fichier de construction nant à copier après une compliation réussie

<target name="action.copy.browserhawk.config" depends="compile.source">
    <copy todir="${App.Web.dir}/bin/" includeemptydirs="false">
        <fileset basedir="${browserhawk.config.dir}">
            <include name="bhawk_bb.dat" />
            <include name="bhawk_sp.dat" />
            <include name="browserhawk.properties" />
            <include name="maindefs.bdd" />
            <include name="maindefs.bdf" />
            <include name="BH_PRO.lic" />
        </fileset>
    </copy>
    <echo message="COPY BROWSERHAWK CONFIG: SUCCESS   ${datetime::now()}" />
</target>
Steve Wright
la source
2
+1 car pour quelqu'un qui utilise nant, c'est toujours une réponse utile
Chris Haines
1

Vous pouvez créer un fichier de commandes pour copier les fichiers et l'exécuter en tant qu'événement post-construction.

jvanderh
la source
J'ai fini par faire cela pour l'un de mes projets (bien que j'aie utilisé un script Python plutôt qu'une chauve-souris).
Fire Lancer