¿Cuáles son ejemplos del mundo real de dependencia gráfico de Gradle?

StackOverflow https://stackoverflow.com/questions/2414281

  •  19-09-2019
  •  | 
  •  

Pregunta

Como se señaló en la documentación , Gradle utiliza un gráfico acíclico dirigido (DAG) para construir una gráfica de la dependencia. Desde mi entendimiento, que tiene ciclos independientes para la evaluación y la ejecución es una característica importante para una herramienta de construcción. p.ej. El Gradle doc afirma que esto permite algunas características que de otro modo sería imposible.

Estoy interesado en ejemplos reales que ilustran el poder de esta función. ¿Cuáles son algunos casos de uso para el cual un gráfico de la dependencia es importante? Estoy especialmente interesado en las historias personales de campo, ya sea con Gradle o una herramienta equipado de manera similar.

Estoy haciendo esto 'wiki de la comunidad' desde el primer momento, ya que será difícil de evaluar una respuesta 'correcta'.

¿Fue útil?

Solución

Esta pregunta provocativa proporcionado motivación para finalmente mirar en Gradle. Todavía no lo he usado, así que sólo puede ofrecer un análisis señaló durante la navegación por los documentos, no historias personales.

Mi primera pregunta era por qué un gráfico dependencia entre tareas Gradle se garantiza que sea acíclico. No he encontrado la respuesta a eso, sino un caso contrario se construye fácilmente, así que supongo que la detección de ciclo es una validación que se ejecuta cuando el gráfico se construye, y la generación falla antes de la ejecución de la primera tarea si existen dependencias cíclicas ilegales. Sin construir primero la gráfica, esta condición de fallo podría no ser descubierto hasta que la construcción es casi completa. Además, la rutina de detección tendría que correr detrás de cada tarea se ejecuta, lo que sería muy ineficiente (siempre y cuando el gráfico se construyó de forma incremental y disponible a nivel mundial, una búsqueda en profundidad sólo sería necesario para encontrar un punto de partida, y la posterior las evaluaciones del ciclo se requieren un mínimo de trabajo, pero el trabajo total seguiría siendo mayor que hacer una única reducción en todo el conjunto de relaciones desde el principio). Me apuntarse la detección temprana como un beneficio importante.

Una dependencia tarea puede ser vago (véase: 4.3 dependencias de tareas, y un ejemplo relacionado en 13.14). dependencias de tareas perezosos no pudieron ser evaluados correctamente hasta que toda la gráfica se construye. Lo mismo es cierto para transitiva (no tarea) la resolución de dependencias, que podría causar innumerables problemas, y requieren repetidas recopilaciones como dependencias adicionales se descubren y resuelven (también requiere repetidas peticiones a un repositorio). La función de reglas de trabajo (13.8) no sería posible tampoco. Estas cuestiones, y probablemente muchos otros, se pueden generalizar al considerar que Gradle utiliza un lenguaje dinámico, y dinámicamente pueden añadir y modificar las tareas, por lo que antes de una evaluación de primer paso, los resultados podrían ser no determinista ya que la ruta de ejecución se construye y se modificado durante el tiempo de ejecución, por lo tanto, diferentes secuencias de evaluación podrían producir de forma arbitraria resultados diferentes si existen dependencias o directivas de comportamiento que son desconocidos hasta más tarde, debido a que no se han creado todavía. (Esto puede ser digno de investigar con algunos ejemplos concretos Si bien es cierto, entonces incluso dos pases no siempre serían suficientes Si A -..> B, B -> C, donde C cambia el comportamiento de A de modo que ya no depende de B, entonces usted tiene un problema. Espero hay algunas mejores prácticas sobre la restricción de metaprogramming con un alcance no local, para no permitir que en las tareas arbitrarias. un ejemplo divertido sería una simulación de una paradoja viaje en el tiempo, donde un nieto mata a su abuelo o se casa con su abuela, que ilustra vívidamente algunos principios éticos prácticos!)

Se puede permitir una mejor situación y el avance de informes sobre una construcción que se está ejecutando. Un TaskExecutionListener ofrece antes / después de ganchos al procesamiento de cada tarea, pero sin saber el número de tareas pendientes, no hay mucho que podría decir sobre el estado que no sea "6 tareas completadas. Sobre foo para ejecutar la tarea." En su lugar, se puede inicializar un TaskExecutionListener con el número de tareas en gradle.taskGraph.whenReady y, a continuación, adjuntarlo a la TaskExecutionGraph. Ahora se podría proporcionar información que permita a los detalles del informe como "6 de 72 tareas completado ahora la ejecución de la tarea foo tiempo restante estimado:.. 38 m 2 h." Esto sería útil para visualizar en una consola para un servidor de integración continua, o si Gradle estaba siendo utilizado para orquestar una gran acumulación de tiempo y las estimaciones de varios proyectos fueron cruciales.

Como se ha señalado por Jerry Bullard, la parte de evaluación del ciclo de vida es crítico para determinar el plan de ejecución, que proporciona información sobre el entorno, ya que el medio ambiente está parcialmente determinada por el contexto de ejecución (Ejemplo 4.15 en el Configurar por la sección DAG ). Además, pude ver que era útil para la optimización de la ejecución. independsubtrazados ent podrían ser transferidos de forma segura a diferentes hilos. Caminar algoritmos para la ejecución puede ser menos intensivo de memoria si no son ingenuos (mi intuición dice que siempre caminando el camino con el mayor número subtrazados va a llevar a una pila más grande que siempre prefiriendo caminos con los mínimos subtrazados).

Un uso interesante de esto podría ser una situación en la que muchos de los componentes de un sistema se apagó inicialmente para apoyar demos y desarrollo incremental. A continuación, durante el desarrollo, en lugar de actualizar la configuración de generación, ya que cada componente se convierte en práctica, la acumulación en sí podría determinar si un subproyecto está listo para su inclusión sin embargo (tal vez trata de agarrar el código, compilarlo, y ejecutar un conjunto de pruebas pre-determinado) . Si es así, la etapa de evaluación revelaría esto, y se incluiría las tareas adecuadas, de lo contrario, selecciona las tareas para los talones. Tal vez hay una dependencia de una base de datos Oracle que no está disponible todavía, y que está utilizando una base de datos integrada en el ínterin. Usted puede dejar que la acumulación y comprueba la accesibilidad, de forma transparente sobre el interruptor cuando se puede, y le dirá que cambió las bases de datos, en lugar de que le dice ella. No puede haber una gran cantidad de usos creativos a lo largo de esas líneas.

Gradle se ve impresionante. Gracias por haber provocado algunas investigaciones!

Otros consejos

Un de la misma documentación ilustra el poder de este enfoque:

  

Como se describe con todo detalle más adelante   (Véase el Capítulo 30, el ciclo de vida de construcción)   Gradle tiene una fase de configuración y   una fase de ejecución. Después de la   fase de configuración Gradle sabe todo   tareas que se deben ejecutar. Gradle   le ofrece un gancho para hacer uso de este   información. Un caso de uso para esto sería   la de comprobar si la tarea es la liberación   parte de las tareas a ejecutar.   En función de esto le puede asignar   diferentes valores a algunas variables.

En otras palabras, se puede enganchar en el proceso de construcción temprana, por lo que puede alterar su curso, según sea necesario. Si algún trabajo de construcción actual ya se había realizado, puede ser demasiado tarde para cambiar.

Estoy evaluando diferentes sistemas de construcción y ahora con Gradle I conseguido añadir código feo que enumera todas las tareas de tipo 'jarra' y los cambia de modo, que cada manifiesto jar incluye 'Build-Número' atributo (que se utiliza más adelante para componer nombres de fichero final):

gradle.taskGraph.whenReady {
    taskGraph ->
    taskGraph.getAllTasks().findAll {
        it instanceof org.gradle.api.tasks.bundling.Jar
    }.each {
        it.getManifest().getAttributes().put('Build-Number', project.buildVersion.buildNumber)
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top