On Github melix / gr8conf2016-intro-software-model
by Cédric Champeau (@CedricChampeau)
speaker { name 'Cédric Champeau' company 'Gradle Inc' oss 'Apache Groovy committer', successes (['Static type checker', 'Static compilation', 'Traits', 'Markup template engine', 'DSLs']) failures Stream.of(bugs), twitter '@CedricChampeau', github 'melix', extraDescription '''Groovy in Action 2 co-author Misc OSS contribs (Gradle plugins, deck2pdf, jlangdetect, ...)''' }
Coupon ctwgr8conftw
Convention based
apply plugin: 'application' allprojects { apply plugin: 'java' }
Coupled
Determining which tasks need to be executed is easy
Determining which tasks need to be configured is hard
Configuring properly is hard (afterEvaluate…)
Polyglot programming
Multiple variants
Scalability
Continuous delivery
Speed
plugins { id 'jvm-component' id 'java-lang' }
model { components { main(JvmLibrarySpec) } }
New way to write plugins
New way to configure builds
But likely to change soon
More in the variant-aware dependency management talk
model { components { app(JvmLibrarySpec) myLib(JvmLibrarySpec) } }
src |-- app | |-- java |-- myLib |-- java
model { components { app(JvmLibrarySpec) { sources { java { dependencies { library 'myLib' } } } } myLib(JvmLibrarySpec) } }
model { components { app(JvmLibrarySpec) { sources { java { dependencies { library 'myLib' module 'org.ow2.asm:asm:5.0.4' } } } } myLib(JvmLibrarySpec) } }
model { components { app(JvmLibrarySpec) { dependencies { library 'myLib' module 'org.ow2.asm:asm:5.0.4' } } myLib(JvmLibrarySpec) } }
model { components { myLib(JvmLibrarySpec) { api { exports 'com.acme.mylib' // not recursive! } } } }
Strong encapsulation
No more private API leakage
Prepare for Jigsaw today!
Compile avoidance
If private API changes
If public API changes in ABI compatible way
model { components { myLib(JvmLibrarySpec) { api { dependencies { library 'com.google.guava:guava:17.0' } } } } }
model { components { myLib(JvmLibrarySpec) { targetPlatform 'java7' targetPlatform 'java8' } } }
myLib.jar for Java 7
myLib.jar for Java 8
Each one can have its own source sets/dependencies.
So far only junit is supported
Adding more frameworks should be easy
plugins { id 'jvm-component' id 'java-lang' id 'junit-test-suite' }
model { components { main(JvmLibrarySpec) } testSuites { test(JUnitTestSuiteSpec) { jUnitVersion '4.12' testing $.components.main } } }
Have JUnit version specified as a first-class model element
Could support multiple target versions of JUnit
Have their own target platforms
Target a specific component
model { javaInstallations { openJdk6(LocalJava) { path '/usr/lib/jvm/jdk1.6.0-amd64' } oracleJre7(LocalJava) { path '/usr/lib/jvm/jre1.7.0' } ibmJdk8(LocalJava) { path '/usr/lib/jvm/jdk1.8.0' } } }
Automatic detection
Automatic selection of toolchain
Test on various platforms
…
model { myPlugin(GradlePlugin) { targetGradleVersions '2.14', '3.0' // ... } }
model { microservice(SpringBootApplication) { springBootVersion '1.3.5' // ... } }
model { dockerImage(DockerImage) { from 'alpine:3.2' // ... } }
Slides and code : https://github.com/melix/gr8conf2016/intro-software-model
Follow me: @CedricChampeau
@Managed interface ImageComponent extends LibrarySpec { String getTitle() void setTitle(String title) List<String> getSizes() void setSizes(List<String> sizes) }
class MyImageRenderingPlugin extends RuleSource { @ComponentType void registerComponent(TypeBuilder<ImageComponent> builder) { } @ComponentType void registerBinary(TypeBuilder<ImageBinary> builder) { } ...
@Managed interface ImageBinary extends BinarySpec { String getTitle() void setTitle(String title) String getSize() void setSize(String size) }
@ComponentBinaries void createBinariesForBinaryComponent(ModelMap<ImageBinary> binaries, ImageComponent library) { library.sizes.each { fontSize -> binaries.create(fontSize) { size = fontSize; title = library.title } } } @BinaryTasks void createRenderingTasks(ModelMap<Task> tasks, ImageBinary binary) { tasks.create(binary.tasks.taskName("render", "svg"), RenderSvg){ it.content = binary.title; it.fontSize = binary.size; it.outputFile = new File(it.project.buildDir, "renderedSvg/${binary.title}_${binary.size}.svg") } }
@Mutate public void registerPlatformResolver(PlatformResolvers platformResolvers) { platformResolvers.register(new JavaPlatformResolver()); } @Model JavaInstallationProbe javaInstallationProbe(ServiceRegistry serviceRegistry) { return serviceRegistry.get(JavaInstallationProbe.class); }