Copiar en el directorio de salida copia la estructura de la carpeta pero solo desea copiar archivos

87

Tengo un VS2008 Quiero copiar ciertos archivos de un directorio a mi /bin/carpeta. He configurado los archivos (ubicados en /common/browserhawk/) en "Copiar al directorio de salida". Sin embargo, también copia la estructura de la carpeta: los archivos se copian en/bin/common/browserhawk/

¿Cómo hago para copiar estos archivos solo /bin/? No quiero almacenarlos en la raíz del sitio web para que se copien correctamente.

Pregunta relacionada: Visual Studio agrega .dll y .pdb al proyecto después de compilar

Steve Wright
fuente

Respuestas:

59

Puede agregar un evento posterior a la compilación para copiar los archivos.
Vaya a las propiedades del proyecto, pestaña Eventos de compilación y agregue lo siguiente a la línea de comando del evento posterior a la compilación:

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

Asegúrese de incluir las comillas si la ruta de su proyecto tiene espacios.

Bill A.
fuente
Gracias por ese consejo, ya que también me ha funcionado en VS2012.
Dib
2
He modificado esto ligeramente en mi caso:xcopy /s /d /y "$(ProjectDir)\stuff" "$(TargetDir)\stuff"
Danny Staple
44

Como no puedo comentar sobre respuestas anteriores, pondré la solución aquí:

Agregando a lo que @PaulAlexander proporcionó, agregue lo siguiente a su archivo .csproj / .vbproj:

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

Esto le permite seleccionar "RootContent" como Acción de compilación en la ventana Propiedades, y se puede acceder a todo a través de la GUI. Una explicación más completa: la opción "AvailableItemName" básicamente crea una nueva lista con nombre a la que puede asignar elementos en el proyecto en la propiedad "Acción de compilación" en la ventana Propiedades. A continuación, puede utilizar esta lista recién creada en cualquier destino que desee (por ejemplo, a través de "@ (RootContent)").

onda de choque
fuente
Buena respuesta, ¡solo usé esto yo mismo para el éxito!
Chris Marisic
También tenga en cuenta que VS 2010 (no estoy seguro acerca de las versiones anteriores) se quejará de AvailableItemNameser un elemento no válido si edita el archivo del proyecto dentro de VS; simplemente ignore la advertencia, funciona de todos modos.
Aaronaught
2
Desafortunadamente, esto solo copia el archivo en el directorio de salida del proyecto al que pertenece el archivo, y no en el directorio de salida del proyecto de inicio. Esto es importante cuando se usa en un proyecto de biblioteca.
Sebastian Krysmanski
2
Esto funciona muy bien para compilar en modo de liberación y depuración con vs2008, pero no parece funcionar cuando se utiliza la publicación con un clic. ¿Alguna sugerencia?
Soenhay
2
No funcionó para mí en vs2015. Se <Target Name="RootOutputCopyTarget" AfterTargets="Build">
corrigió
44

Si edita el .csproj / .vbproj en un editor de texto, puede controlar dónde se coloca el archivo en el directorio de salida, y también qué nombre tendrá el archivo en el directorio de salida. Por ejemplo:

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

Esto pondrá el archivo content\someContent.txten bin\someContentInOutputDirectory.txt. También puede elegir un subdirectorio binsi lo desea; simplemente agréguelo al elemento Link.

Daniel Yankowsky
fuente
3
Vaya, tuve suerte de necesitar esto ahora y no hace dos días. Gracias; ¡esto es genial!
Asera
2
Oh dios mío, gracias. Acabo de pasar 6 horas tratando de arreglar algo de basura en las esquinas donde VS no estaba copiando .dll de una manera inteligente. Esta es la verdadera respuesta a la vida, el universo y todo.
Brandon
5
Esta es, con mucho, la mejor solución
PhilHdt
1
Una vez que hice esto y volví a cargar el proyecto en Visual Studio, los archivos de dependencia desaparecieron del explorador de soluciones como si no estuvieran incluidos en el proyecto. Sin embargo, todavía se construye como se esperaba y se copia a la salida como se desea. Como solución temporal, actualmente estoy agregando cada archivo dos veces; una vez sin acción, y una vez con 'copiar a salida' configurado.
Éliette
1
Este no es el uso previsto de esta etiqueta. En VS2013, esto arroja una advertencia al cargar el proyecto, y el archivo no está visible como agregado al proyecto porque es el directorio del proyecto.
jpmc26
15

Creo que el comando XCOPY maneja mejor los directorios y archivos. Por lo tanto,

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

Lo que permite crear carpetas fuera del directorio de destino.

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

La carpeta del proyecto / estructura de archivo de:

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

Se convierte en:

    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
fuente
/Dtambién puede ser útil para evitar sobrescribir posibles cambios.
KurzedMetal
10

Agregue lo siguiente a su archivo .csproj / .vbproj

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

Luego cambie la Acción de compilación de los archivos que desee en la carpeta raíz a RootContent.

Paul Alexander
fuente
No a través de los diálogos ... pero puede editar su proyecto en VS. Haga clic con el botón derecho en el proyecto y seleccione Descargar proyecto. Luego haga clic derecho y seleccione Editar. Luego, puede editar el archivo MSBuild que es su proyecto.
Paul Alexander
2
Gracias, esto parece útil. Desafortunadamente, incluso después de agregar su fragmento al archivo .vbproj, RootContentno aparece en la lista desplegable "Acción de compilación" e ingresarlo manualmente da como resultado un error "El valor de propiedad no es válido" de Visual Studio. ¿Qué me perdí?
Heinzi
No funciona con el proyecto de aplicación de consola de Visual Studio 2010 C #.
AMissico
No funciona con el proyecto de aplicación de consola de Visual Studio 2010 VB.NET.
AMissico
No funciona con el proyecto de aplicación de consola Visual Studio 2008 C #.
AMissico
5

Lo he usado en VS2010, VS2015, VS2017 y VS2019. Prefiero esta solución porque:

  1. El XML es reutilizable en cualquier proyecto.
  2. El "RootContent" se elige como una acción de compilación en la interfaz de usuario de Visual Studio, como cualquier otro "Contenido".
  3. El "CopyToOutputDirectory" se obedece, tal como cabría esperar
  4. El RootContent se agrega a la salida del proyecto: se lleva a cabo a través de Project-References, obedece a "Clean", etc.
  5. El RootContent se puede especificar con un comodín, conservando la estructura de carpetas recursivas:
<RootContent Include="common\browserhawk\**">
  <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</RootContent>

Hacia el comienzo del archivo del proyecto:

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

Tomado de esta respuesta

Después de la importación de .targets de Microsoft:

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

Tomado de esta respuesta

MattGerg
fuente
Esto es bueno; cambiaría lo RootContentque implica "codificado" para CustomContentindicar que se trata de contenido especializado que estamos agregando a este proyecto y que necesitamos copiar de esta manera en particular. Además, necesitaba TargetPath=%(RecursiveDir)%(Filename)%(Extension)recrear la estructura de carpetas de los CustomContentarchivos especificados a la ruta de salida.
Jonno
@Jonno El objetivo es copiar los archivos directamente en el directorio raíz de salida, independientemente de RecursiveDirectory. La acción de compilación de "Contenido" incorporada ya nos proporciona un mecanismo para copiar mientras se mantiene el RecursiveDirectory.
MattGerg
No he tenido la oportunidad de probar esto en un tiempo, pero ¿la configuración de la acción de compilación "Contenido" no haría que los archivos de abajo /common/browserhawk/se copiaran /bin/common/browserhawk/como dijo el OP? IIRC, mi intención era /common/browserhawk/a.txtterminar en /bin/a.txtpero permitir la recursividad desde allí hacia abajo, por lo que /common/browserhawk/secret/stuff.pngtermina en /bin/secret/stuff.png.
Jonno
@Jonno Ok, sí, eso tiene mucho sentido ahora. Actualicé la respuesta para incluir el %(RecursiveDirectory). Esto es realmente genial, porque además de seleccionar archivos individuales en el IDE, también puede especificar varios archivos con comodines. Al usar el **comodín, se conservará toda la estructura de la carpeta.
MattGerg
1
¡Muchas gracias por tan buena respuesta! Creo que esta respuesta es la respuesta correcta debido a lo siguiente: 1. Sin cmds externos 2. multiplataforma
George Anisimov
2

Terminé agregando un paso al archivo de compilación nant para copiar después de una compilación exitosa

<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
fuente
2
+1 porque para alguien que usa nant, esta sigue siendo una respuesta útil
Chris Haines
1

Puede crear un archivo por lotes para copiar los archivos y ejecutarlo como un evento posterior a la compilación.

jvanderh
fuente
Terminé haciendo esto para uno de mis proyectos (aunque usé un script de Python en lugar de un murciélago).
Fire Lancer