build automation - traduccion - Múltiples configuraciones gradle files para la construcción de múltiples proyectos
gradle tutorial (6)
Tengo la siguiente estructura de proyecto
-->Starnderd Location
-->Project1
-->settings.gradle
-->build.gradle
-->Subproject11
-->build.gradle
-->Subproject12
-->build.gradle
-->Project2
-->settings.gradle
-->build.gradle
-->Subproject21
-->build.gradle
-->Subproject22
-->build.gradle
-->build.gradle
-->settings.gradle
Idea de la estructura del proyecto anterior es que tenemos proyectos múltiples que contienen subproyectos, cada proyecto puede tener dependencias a otros proyectos. Además, los subproyectos dentro del proyecto pueden tener dependencias con otros subproyectos dentro del mismo proyecto. Los proyectos se especificarán en settings.gradle en la raíz. También settings.gradle dentro de cada proyecto dirá cuáles son los subproyectos de ese proyecto en particular.
Mi settings.gradle en la raíz sería como
include ''Project1'',
''Project2''
y Project1 settings.gradle se verá como
include ''SubProject11''
''SubProject12''
otros órdenes de depndecy se definen en los respectivos archivos build.gradle Si rand gradle clean build install dentro de la ubicación raíz (Standar location) no parece usar configuraciones en el archivo Project level settings.gradle.
¿Qué estoy haciendo aquí mal?
Actualmente, Gradle solo admite una sola settings.gradle
. Grabar archivos por compilación. Esto puede cambiar en el futuro.
Aprovechando respuestas anteriores, esto es con lo que salí.
interface Includer {
def include(String... args)
}
def applyFrom(String folder) {
apply from: folder + ''/settings.gradle''
def includer = [
include: { args ->
args.each {
project(it.startsWith('':'') ? it : '':'' + it).projectDir =
new File(rootDir, folder + "/" + (it.startsWith('':'') ? it.substring(1) : it).replace('':'', ''/''))
}
}] as Includer
apply from: folder + ''/settings.gradle'', to: includer
}
applyFrom(''A'')
applyFrom(''B'')
La ventaja es no duplicación.
Pude resolver este problema de una manera relativamente limpia. ¡Las mejoras son ciertamente bienvenidas!
A pesar de que Gradle no es compatible con varias settings.gradle
secuencias de comandos de fábrica, es posible crear subproyectos individuales cada uno con su propio archivo settings.gradle
. Digamos que tiene un proyecto múltiple A que depende de un proyecto múltiple B, cada uno con sus propios subproyectos. Su estructura de directorio puede ser similar a:
A
- settings.gradle
- foo
- faz
/ B
- settings.gradle
- bar
- bap
Fuera de la caja, Gradle espera que A/settings.gradle
tenga el siguiente aspecto:
include '':foo'', '':faz'', ''B:bar'', ''B:bap''
El problema con esto es que cada vez que B agrega un nuevo proyecto, A/settings.gradle
también debe cambiar incluso si el nuevo proyecto solo lo usa B. Para evitar esta situación, puede intentar apply
B/settings.gradle
en A/settings.gradle
lugar de agregar declaraciones redundantes:
apply from: ''B/settings.gradle''
include '':foo'', '':faz''
Si prueba esto, encontrará que Gradle falla porque genera el projectDir
incorrecto para :bar
y :bap
. Supone erróneamente que B''s includes son relativos a settingsDir
que resulta ser A/
cuando se invoca Gradle desde la raíz del proyecto. Para solucionarlo, puede agregar otro script como B/settings-parent.gradle
(el nombre exacto no es significativo):
apply from: ''settings.gradle''
rootProject.children.each { project ->
String relativeProjectPath = project.projectDir.path.replace(settingsDir.path, "")
project.projectDir = new File("B/$relativeProjectPath")
}
Esto elimina settingsDir.path
y prefijos de la ruta con B/
. Esto se puede extender a varias capas de archivos de settings[-parent].gradle
haciendo que cada capa se agregue a la ruta. Ahora aplicará esta secuencia de comandos a A/settings.gradle
:
apply from: ''B/settings-parent.gradle''
include '':foo'', '':faz''
Con este esquema, los nuevos proyectos B no rompen innecesariamente A/settings.gradle
y todos los proyectos pueden utilizarse sin referencia explícita al subproyecto B. Por ejemplo, si '':foo''
quería usar ''B:bap''
, simplemente puede declarar:
compile project('':bap'')
Si está utilizando Gradle 3.x, intente includeBuild (): https://docs.gradle.org/current/userguide/composite_builds.html
// settings.gradle
includeBuild ''./Project1''
includeBuild ''./Project2''
Si está utilizando Gradle 2.x, he escrito una demostración para esta función. Espero que te ayude: https://github.com/xujiaao/gradle-composite-build-demo
// settings.gradle
def includeProject(String path, Closure closure) {
...
apply {
from ...
to new SettingsProxy(...)
}
}
class SettingsProxy {
...
public getRootProject() { ... }
public void include(String... paths) {
for (String path : paths) {
if (!mProjectSpec.accept(path)) {
continue
}
def descendantPath = generateDescendantPath(path)
mSettings.include(descendantPath)
def descendantProjectDir = new File(mProject.projectDir, path.replace('':'', ''/''))
mSettings.project(descendantPath).projectDir = descendantProjectDir
}
}
}
También he investigado esto y puedes hacerlo, ¡pero es muy feo! La razón por la que esto funciona para nosotros es que la gran mayoría del tiempo, solo queremos construir desde el nivel más alto.
Si te sirve de ayuda, lo que debes hacer es que el archivo settings.gradle más adecuado haga referencia a cada proyecto-subproyecto directamente. Haz que esto funcione primero.
Luego, si Project1 y Project2 (y así sucesivamente) pueden construirse independientemente entre sí, puede crear un archivo local settings.gradle para ese proyecto. Dado que, como dije antes, esto no es lo que solemos hacer, llamamos a este archivo settings.project1. Si queremos usar este archivo, lo copiamos a settings.gradle. Sé feo.
Pero en realidad empeora :) Una vez que coloque este archivo settings.gradle en su lugar, la compilación desde Project1 ya no verá el archivo build.gradle de nivel superior donde probablemente haya necesitado elementos definidos. Para invocar esto, necesitaría agregar algo como esto a cada archivo build.gradle a nivel de proyecto:
if (project.hasProperty(''local'')) {
apply from: ''../build.gradle''
}
A continuación, puede ejecutar la compilación como: gradle
Feo, pero si lo necesitas, al menos funciona. Y en aras de la divulgación completa, al haber implementado esto hace un par de semanas, ninguno de los desarrolladores lo ha necesitado ni lo ha utilizado. Probablemente lo elimine en un par de semanas si no se usa.
Recuerde que si construye desde el subproyecto en sí, solo se construirá ese subproyecto (y cualquier proyecto dependiente) (aunque se compilarán / evaluarán todos los scripts de Gradle).
como este tema ya se ha cruzado en mi trabajo diario bastante seguido y la mejora ( GRADLE-803 ) todavía está abierta, me gustaría compartir mi enfoque también:
A primera vista, se parece a la answer James Wald, pero tiene una diferencia. No necesita dividir los archivos de configuración de alguna manera en el subproyecto. Hay una manera limpia de hacer todo en el superproyecto si eso es aceptable para usted. Normalmente, sus pequeños subproyectos no deberían preocuparse por los superproyectos que los rodean. Incluyen sus sub dependencias y eso es todo. También debería ser irrelevante cómo se nombra el directorio del módulo; en el enfoque de Wald, el módulo necesita saber su nombre de directorio (''B'') aquí:
project.projectDir = new File("B/$relativeProjectPath")
En contraste, generalmente, un súper proyecto conoce bien sus subproyectos y directorios, porque podrían ser submódulos de Git, por ejemplo, que tienen nombres de arreglos bien definidos que pueden, desde la perspectiva del superproyecto, ser referenciados de manera segura.
Esa es mi configuración (usando Gradle 2.4):
Super Project
├── build.gradle
├── settings.gradle (include ''A'' include ''B'')
├── <Subproject A>
├── build.gradle
├── settings.gradle (include ''subA'')
├── <Subsubproject subA>
├── build.gradle
├── <Subproject B>
├── build.gradle
├── settings.gradle (include ''subB'')
├── <Subsubproject subB>
├── build.gradle
En el super project settings.gradle, ahora puede codificar lo siguiente:
include ''A''
include ''B''
apply from: ''A/settings.gradle''
apply from: ''B/settings.gradle''
project('':subA'').projectDir = new File(rootDir, ''A/subA'')
project('':subB'').projectDir = new File(rootDir, ''B/subB'')
Todavía parece bastante prolijo (y aún no agrega un comportamiento jerárquico real), pero mantiene el esfuerzo extra en el súper proyecto donde normalmente necesita saber todo sobre los módulos contenidos de todos modos.
El resto es bastante sencillo de nuevo.
Si desea ver mi enfoque en la práctica, lea la sección 5.) de esta publicación de blog , donde explícitamente requiero esta independencia entre los módulos o simplemente reviso mi proyecto github en los puntos de referencia entre idiomas . Pero ten en cuenta que necesitas una cadena de herramientas compiladora nativa en ejecución como gcc o Clang para ejecutarla;)
¡Espero que esto ayude! Cheers Ben