own - Construcción de NuGet multi-marco con símbolos para la gestión interna de dependencias
nuget spec (3)
Tal vez estoy presionando el sobre aquí, pero estoy desesperado por aprovechar NuGet para facilitar el infierno DLL en el que me he encontrado.
Tenemos 4 productos principales que todos viven en repositorios Mercurial interrelacionados. Todos ellos "comparten" 3 ensamblajes principales y luego todo lo demás es más o menos específico del producto. Ahora es muy difícil de administrar porque un producto se ha actualizado a .NET 4.0 y está usando dependencias externas que requieren .NET 4.0, mientras que otro producto está atascado en .NET 3.5 por razones en las que ni siquiera quiero entrar.
Por lo tanto, hemos perdido nuestra capacidad de combinar diferencias entre productos.
Para solucionarlo, quiero sacar los 3 ensamblajes principales y convertirlos en su propio proyecto con su propio ciclo de lanzamiento, y tener el cuidado de asegurarme de que puedan compilar tanto contra .NET 3.5 y 4.0, y luego convertirlos en Paquetes de NuGet que contienen múltiples versiones de framework.
PERO, también quiero que los desarrolladores puedan explorar la fuente de estos proyectos.
Así que configuro un servidor NuGet privado y un servidor SymbolSource privado . Luego fusioné cuidadosamente todos los cambios de todos los repositorios juntos, y deseché todo, excepto mis ensamblajes centrales. Luego edité cuidadosamente los archivos .csproj para que, en lugar de la plataforma AnyCPU, cada proyecto tenga objetivos de plataforma de 3.5 y 4.0, que especifiquen constantes condicionales (para controlar características específicas de la plataforma como System.Dynamic) y establezca la versión de la estructura.
Luego configuro las configuraciones de la solución para "3.5 Debug", "3.5 Release", "4.0 Debug" y "4.0 Release". Cada uno apunta a la Configuración apropiada (Depuración o Lanzamiento) y la Plataforma (3.5 o 4.0).
Puedo construir todo bien dentro de Visual Studio para cualquier plataforma. Ahora tengo un problema cuando se trata de NuGet, porque hay dos formas de crear un paquete, y ambas tienen una debilidad, a menos que me esté perdiendo algo:
Paquete por archivo de proyecto
nuget pack MyProject.csproj -Build -Symbols -Version <insert-from-build-server> -Properties "Configuration=Release;Platform=3.5;"
Los problemas con esto son:
- Mientras que la versión 3.5 está construida y empaquetada, la salida dice "Creación de proyecto para el marco de trabajo ''.NETFramework, versión = v4.0''".
- Si desempaqueto los paquetes resultantes, los ensamblajes están bajo
lib/net40
cual es incorrecto. - No creo que haya ninguna forma de empaquetar 2 destinos de framework de esta manera, tienes que hacerlo de la otra manera con carpetas y convenciones.
- Estoy dispuesto a aceptar que no se pueden empaquetar los marcos y crear 2 paquetes llamados MyProject (que haría como 4.0) y MyProject.V35 ... sin embargo, no puedo averiguar cómo tener el mismo proyecto y nuspec y terminar con 2 resultados diferentes con diferentes ids.
Paquete por archivo Nuspec
Con este método, tengo que hacer todo el msbuilding y luego hacer un montón de copia de archivos para configurar una estructura de carpetas como
* MyProject.nuspec
* net40
* MyProject.dll
* MyProject.pdb
* net35
* MyProject.dll
* MyProject.pdb
Luego puedo ejecutar el nuget pack MyProject.nuspec
pero luego no hay una fuente que vaya con los símbolos, porque sin el archivo .csproj, NuGet no tiene forma de averiguar dónde obtener todos los archivos fuente, y no veo ninguna. documentación sobre cómo hacer esto usando las convenciones de directorio tampoco.
Así que mis preguntas son:
- ¿Hay alguna manera de agregar archivos de origen a un paquete basado en convenciones?
- ¿Hay una manera de empaquetar un paquete basado en proyecto dos veces con diferentes identificadores?
- ¿Hay otra avenida que quizás no haya considerado?
Cualquier pensamiento sería muy apreciado.
¿Sabes que hay una tercera opción? Cuando se dirige a un archivo csproj, también buscará un archivo nuspec con el mismo nombre que su archivo de proyecto (myProject.csproj -> myProject.nuspec). Esto significa que puede agregar metadatos adicionales al paquete resultante definiéndolo en el archivo nuspec, mientras sigue apuntando a su archivo csproj. En esencia, terminará con un paquete que contiene los metadatos combinados de su archivo csproj y su archivo nuspec.
En su escenario específico, si desea empaquetar múltiples construcciones de plataforma del mismo proyecto, tendrá que compilar esos proyectos primero antes de empaquetar utilizando el nuspec.
Le aconsejo que cree dos proyectos , uno dirigido a NET35, el otro dirigido a NET40 y agregando los archivos como enlaces a uno de los proyectos. Como tal, puede generar ambos proyectos y empaquetar todos los resultados en un paquete NuGet usando un archivo nuspec .
Ahora, en cuanto a los símbolos, creo que podría tener un segundo archivo nuspec (por ejemplo, myProject.symbols.nuspec), donde podría agregar todo el contenido del proyecto (fuentes, etc.) utilizando caracteres comodín, similares a los que se muestran a continuación.
<file src="myProject35/**/*.cs" target="src" />
<file src="myProject40/bin/Release/*.dll" target="lib/net40" />
<file src="myProject40/bin/Release/*.pdb" target="lib/net40" />
<file src="myProject35/bin/Release/*.dll" target="lib/net35" />
<file src="myProject35/bin/Release/*.pdb" target="lib/net35" />
Espero que esto ayude o al menos le brinde información para encontrar una salida :)
Saludos xavier
La respuesta de Xavier me guió en la dirección correcta, y también informó mi búsqueda en Google. No estaba completamente al tanto de las declaraciones del archivo, y al buscar en esa línea, encontré la publicación de Joshua Flanagan, Consejos para construir paquetes de NuGet , que es excelente. Xavier y Joshua juntos me enseñaron algunas cosas:
- No es necesario ensamblar un árbol de archivos que cumpla con las convenciones para construir un paquete. Es mucho mejor usar el elemento de archivo para seleccionar archivos y dirigirlos a un directorio de destino dentro del paquete de NuGet ensamblado.
- El indicador de símbolos de NuGet no solo funciona para empaquetar en un archivo .csproj. Cuando lo use en un archivo
.csproj
, entonces claro, así es como se da cuenta de cómo empaquetar todos sus archivos de origen. Pero también puede usar-Symbols
en un archivo.nuspec
que incluya la fuente a través de los elementos del archivo. El paquete normal de NuGet no incluirá el directorio src, pero sí lo hará el paquete de símbolos.
Ahora, permítame describir mi proceso de compilación como ocurre en mi servidor de CI:
- Cree la solución utilizando la configuración de la solución "3.5 Release".
- Cree la solución utilizando la configuración de la solución "4.0 Release".
- Use ILMerge.exe para internalizar algunos ensamblajes. Tengo estos resultados para (por ejemplo)
bin/Release-3.5/merged
por lo que no tengo que simular el cambio de nombre del ensamblado de destino a temp.dll antes de usarlo en la combinación. - Construye el paquete contra el
.nuspec
en Powershell.
Aquí está el comando del paquete:
nuget pack src/MyProject/MyProject.nuspec -OutputDirectory ./output -Build -Symbols -Version $Version
Tenga en cuenta que $ Version se transfiere desde el servidor de compilación para que pueda usar su número de compilación como la última parte de la versión.
Aquí está el archivo .nuspec:
<?xml version="1.0"?>
<package>
<metadata>
<id>MyProject</id>
<version>0.0.0</version>
<title>MyProject</title>
<authors>David Boike</authors>
<owners>David Boike</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>MyProject</description>
<releaseNotes></releaseNotes>
<copyright>Copyright 2012</copyright>
<tags>my tags</tags>
</metadata>
<files>
<file src="bin/Release-4.0/merged/MyProject.dll" target="lib/net40" />
<file src="bin/Release-4.0/merged/MyProject.pdb" target="lib/net40" />
<file src="bin/Release-4.0/MyProject.xml" target="lib/net40" />
<file src="bin/Release-3.5/merged/MyProject.dll" target="lib/net35" />
<file src="bin/Release-3.5/merged/MyProject.pdb" target="lib/net35" />
<file src="bin/Release-3.5/MyProject.xml" target="lib/net35" />
<file src="**/*.cs" target="src" />
</files>
</package>
Tenga en cuenta que he eliminado muchos de los elementos más informativos de mi nuspec porque simplemente no importa para un proyecto interno como este.
El resultado es un paquete para mi servidor NuGet privado que contiene DLL, PDB y documentación XML para el ensamblaje de .NET 3.5 y 4.0, y luego un paquete de símbolos separado para mi SymbolServer privado que incluye todo lo anterior más la fuente. Esto es muy fácil de ver con el Explorador de paquetes de NuGet, que le recomiendo que descargue.
Finalmente, probé todo y con la configuración de Visual Studio sugerida en symbolsource.org (excepto con mi propio servidor de símbolos privado) pude depurar el código y acceder fácilmente a la fuente.
Gracias de nuevo a Xavier por guiarme por el camino correcto!
Verifique las nuevas funciones en NuGet 2.5 relacionadas con las referencias dependientes de la versión del marco: http://docs.nuget.org/docs/release-notes/nuget-2.5
Puede ser una opción para que use configuraciones de compilación con elementos de referencias condicionales en los archivos csproj (conditinal en TargetFrameworkVersion), luego ejecute su compilación en todas las configuraciones y produzca resultados para net35 y net40 con la orientación opcional de referencias en su nupkg.