Crear zip delta para superponer la installation anterior

Fondo

Usamos Gradle en el trabajo para build nuestro software (Java / C ++ / MATLAB), package por variaciones de los clientes de los files de configuration y montar una installation agregada final de todo.

Una parte de las "variaciones del cliente" es una estructura de directory regular que tiene un set de reglas de copydo / estratificación, por lo que podemos compartir la mayor cantidad posible de la configuration entre las variaciones.

Lo logramos hoy con una tarea copyConfiguration que se parece al repository inventado que recreé aquí . Cada variación se considera un subproyecto separado de todo el proyecto "config". Copiamos en order (1, 2, project.name) con files en project.name sobrescribiendo files con nombres idénticos de 1 o 2 (lo mismo vale para 2 sobre 1). Construimos un directory de destino y luego lo comstackmos para su deployment. He inventado los nombres en el ejemplo, pero considero que hay una docena de subdirectorys de "componentes" (aaa, bbb, etc.) y 10-15 subproyectos (con una longitud máxima de 'orderToCopy' de alnetworkingedor de 5). Los nombres de file no son únicos a nivel mundial en los diferentes componentes o subproyectos (por lo que no puede confiar en el file A solo existente bajo aaa o nunca bajo un directory de subproyecto diferente).

Puntos de dolor

Cada semana, volvemos a instalar varias variaciones en function de qué clientes recibirán la próxima versión. En este momento, el process de installation es dolorosamente manual y lento (generalmente de la noche a la mañana para unos pocos cientos de serveres), por lo que a less que sea catastrófico, evitamos volver a lanzar una compilation completa de nuestras configuraciones hasta la próxima installation. Logramos hacer mediante el uso de un sistema interno de "aplicación de parches" que nos permite superponer cambios sin tener que volver a instalar todo. Estos parches están construidos a mano en function de lo que "necesita" ser reparado. Esto a veces es doloroso cuando varias personas repiten el mismo file varias veces o alguien copy un file con el mismo nombre en el destino equivocado (por ejemplo, tenemos múltiples log4j.properties, pero solo uno es correcto en un directory determinado).

También con frecuencia tenemos situaciones en las que la variación de un cliente (cliente antiguo) deberá comunicarse con la variación más nueva de otro (cliente nuevo). Esto generalmente se maneja construyendo un parche similar al anterior en la parte superior de la última configuration entregada del cliente anterior cuando entregamos el cliente nuevo. Esto es aún más doloroso y estresante, ya que a veces se pueden build unos encima de otros y todos los parches se crean a mano (por ejemplo, copie este file aquí, cambie el nombre de este file, etc.). Esto solía ser mucho peor antes de que tuviéramos un VCS que admitiera la bifurcación …

¿Problema / objective deseado?

He estado pensando en esto de manera intermitente durante varios meses, pero no he encontrado una buena solución. Lo que me gustaría hacer es confiar en la información del VCS (git, en nuestro caso) o alguna información previa (artefactos, área de construcción, etc.) para build un file zip delta para cada variación desde un punto de reference dado. En mi repo de ejemplo, si src / main / dist / aaa / 2 / fileA cambiaran, en un mundo ideal, el zip delta delta estaría vacío para el subproyecto1 y solo contendría el file modificado para el subproyecto2.

Ideas

Intenté hacer una compilation completa, download la compilation anterior (basada en una propiedad de línea de command de Gradle), extraerla y luego distinguir los dos directorys de salida. Creo que puedo hacer que esto funcione, pero parece sucio y funciona fuera de Gradle. Después de señalarme los parches delta-binarys que usaba Mozilla, encontré una librería de xdelta binary diff para Java e hice una testing de concepto al usarla.

¿Alguna otra idea? ¿Hay alguna forma mejor o más declarativa o idiomática de hacer algo como esto? Si hay alguna manera de volver a trabajar en copyConfiguration para hacerlo más fácil, estoy abierto a las ideas.

Ideas abandonadas

  1. He podido get una list de files modificados usando git whatchanged y luego excluyo () files que no están en mi list en el cierre de cada file {}. Esto funciona siempre que se modifiquen los files "hoja". Si src / main / dist / aaa / 2 / fileA cambiara, terminaría excluyendo aaa / 1 / fileA y aaa / subproject1 / fileA y obtendría los contenidos incorrectos para la compilation de mi parche. Esto tampoco maneja las eliminaciones en las que se debe usar un file en 1 o 2 (porque el file de mayor prioridad se ha eliminado). También hay un caso de eliminación de todas las apariciones de un file, por lo que no deberíamos instalar nada, pero creo que es un caso límite que puede ignorarse por el momento. Esto parecía realmente difícil de resolver en todos los casos de esquina.

  2. También intenté simplemente tomar el nombre base de todos los files modificados, pero esto sobre-selecciona nombres comunes de files y hace que el parche contenga demasiado. por ejemplo, si aaa / 2 / fileA cambiara, terminaríamos construyendo un parche para el subproyecto1 que contenía aaa / data / fileA y bbb / data / fileA (cuando no hay files es la respuesta "correcta"). No me gustó porque el zip del parche contenía files sin modificar y no manejaba eliminaciones / movimientos.

  3. También he pensado, pero aún no lo he intentado, haciendo algo similar a lo de arriba. Verifique la confirmación previa, compilation, verificación de la confirmación para build el parche y enganche en la function de compilation incremental de Gradle. Todavía estamos usando Gradle 1.1, por lo que la funcionalidad aún no está disponible para mí. Esto fue doloroso y requirió un guión para ejecutar a Gradle dos veces.

¡Gracias por leer!