SlideShare ist ein Scribd-Unternehmen logo
1 von 15
Gradle Plugins 101
Getting up and running
@ddimitrov
Gradle bootstraps your build extensions
If you put some code in a project named buildSrc, directly under the
root of your build, Gradle will automatically compile them and add them
to the classpath of the main build.
This allows you to quickly hack plugins, tasks or utility classes that you
use in your build scripts.
https://docs.gradle.org/current/userguide/organizing_build_logic.html#sec:build_sources
You can put all the code for your plugin in one file
class MyPlug implements Plugin<Project> {
void apply(Project project) {
def plug = project.extensions.create('timer', MyPlugExtension, project)
def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask
countClasses.input = project.file(project.buildDir, 'classes')
}
}
class MyPlugExtension {
Project project
void start() { project.ext.timestamp = System.currentTimeMillis() }
void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") }
}
class CountClassesTask extends DefaultTask {
@InputDirectory File input
@OutputFile File output
@TaskAction
void generateClassCountFile() {
def counter=0
def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor
Files.walkFileTree(input.toPath(),cfv)
output.text = "$counter files"
}
}
Not necessarily a good idea, but I can and I often do
Use extensions to expose plugin level configuration
class MyPlug implements Plugin<Project> {
void apply(Project project) {
def plug = project.extensions.create('timer', MyPlugExtension, project)
def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask
countClasses.input = project.file(project.buildDir, 'classes')
}
}
class MyPlugExtension {
Project project
void start() { project.ext.timestamp = System.currentTimeMillis() }
void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") }
}
class CountClassesTask extends DefaultTask {
@InputDirectory File input
@OutputFile File output
@TaskAction
void generateClassCountFile() {
def counter=0
def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor
Files.walkFileTree(input.toPath(),cfv)
output.text = "$counter files"
}
}
That means mostly settings.
Actually, you can put utility methods too,
but better keep them to config phase.
P.S. if you are not sure what the pre
paragraph means - just do settings.
Use tasks to do stuff
class MyPlug implements Plugin<Project> {
void apply(Project project) {
def plug = project.extensions.create('timer', MyPlugExtension, project)
def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask
countClasses.input = project.file(project.buildDir, 'classes')
}
}
class MyPlugExtension {
Project project
void start() { project.ext.timestamp = System.currentTimeMillis() }
void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") }
}
class CountClassesTask extends DefaultTask {
@InputDirectory File input
@OutputFile File output
@TaskAction
void generateClassCountFile() {
def counter=0
def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor
Files.walkFileTree(input.toPath(),cfv)
output.text = "$counter files"
}
}
BTW, these strings are the names by
which the tasks and extensions would
appear in your build script when you apply
the plugin.
Create a property file referring to your plugin class
class MyPlug implements Plugin<Project> {
void apply(Project project) {
def plug = project.extensions.create('timer', MyPlugExtension, project)
def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask
countClasses.input = project.file(project.buildDir, 'classes')
}
}
class MyPlugExtension {
Project project
void start() { project.ext.timestamp = System.currentTimeMillis() }
void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") }
}
class CountClassesTask extends DefaultTask {
@InputDirectory File input
@OutputFile File output
@TaskAction
void generateClassCountFile() {
def counter=0
def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor
Files.walkFileTree(input.toPath(),cfv)
output.text = "$counter files"
}
}
implementation-class=com.bar.MyPlug
Apply the plugin using the name of the props file
class MyPlug implements Plugin<Project> {
void apply(Project project) {
def plug = project.extensions.create('timer', MyPlugExtension, project)
def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask
countClasses.input = project.file(project.buildDir, 'classes')
}
}
class MyPlugExtension {
Project project
void start() { project.ext.timestamp = System.currentTimeMillis() }
void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") }
}
class CountClassesTask extends DefaultTask {
@InputDirectory File input
@OutputFile File output
@TaskAction
void generateClassCountFile() {
def counter=0
def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor
Files.walkFileTree(input.toPath(),cfv)
output.text = "$counter files"
}
}
implementation-class=com.bar.MyPlug
apply plugin: 'my-plug'
timer.start()
tasks.countClasses.output = file('class-count.txt')
timer.end()
Your extension and predefined tasks are applied
class MyPlug implements Plugin<Project> {
void apply(Project project) {
def plug = project.extensions.create('timer', MyPlugExtension, project)
def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask
countClasses.input = project.file(project.buildDir, 'classes')
}
}
class MyPlugExtension {
Project project
void start() { project.ext.timestamp = System.currentTimeMillis() }
void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") }
}
class CountClassesTask extends DefaultTask {
@InputDirectory File input
@OutputFile File output
@TaskAction
void generateClassCountFile() {
def counter=0
def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor
Files.walkFileTree(input.toPath(),cfv)
output.text = "$counter files"
}
}
implementation-class=com.bar.MyPlug
apply plugin: 'my-plug'
timer.start()
tasks.countClasses.output = file('class-count.txt')
timer.end()
You can call methods and set props on them
class MyPlug implements Plugin<Project> {
void apply(Project project) {
def plug = project.extensions.create('timer', MyPlugExtension, project)
def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask
countClasses.input = project.file(project.buildDir, 'classes')
}
}
class MyPlugExtension {
Project project
void start() { project.ext.timestamp = System.currentTimeMillis() }
void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") }
}
class CountClassesTask extends DefaultTask {
@InputDirectory File input
@OutputFile File output
@TaskAction
void generateClassCountFile() {
def counter=0
def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor
Files.walkFileTree(input.toPath(),cfv)
output.text = "$counter files"
}
}
implementation-class=com.bar.MyPlug
apply plugin: 'my-plug'
timer.start()
tasks.countClasses.output = file('class-count.txt')
timer.end()
rootProject.name = 'tasks-and-plugins'
So, this is what the build looks like - modular...
class MyPlug implements Plugin<Project> {
void apply(Project project) {
def plug = project.extensions.create('timer', MyPlugExtension, project)
def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask
countClasses.input = project.file(project.buildDir, 'classes')
}
}
class MyPlugExtension {
Project project
void start() { project.ext.timestamp = System.currentTimeMillis() }
void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") }
}
class CountClassesTask extends DefaultTask {
@InputDirectory File input
@OutputFile File output
@TaskAction
void generateClassCountFile() {
def counter=0
def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor
Files.walkFileTree(input.toPath(),cfv)
output.text = "$counter files"
}
}
implementation-class=com.bar.MyPlug
apply plugin: 'my-plug'
timer.start()
tasks.countClasses.output = file('class-count.txt')
timer.end()
...and cohesive
class MyPlug implements Plugin<Project> {
void apply(Project project) {
def plug = project.extensions.create('timer', MyPlugExtension, project)
def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask
countClasses.input = project.file(project.buildDir, 'classes')
}
}
class MyPlugExtension {
Project project
void start() { project.ext.timestamp = System.currentTimeMillis() }
void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") }
}
class CountClassesTask extends DefaultTask {
@InputDirectory File input
@OutputFile File output
@TaskAction
void generateClassCountFile() {
def counter=0
def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor
Files.walkFileTree(input.toPath(),cfv)
output.text = "$counter files"
}
}
implementation-class=com.bar.MyPlug
apply plugin: 'my-plug'
timer.start()
tasks.countClasses.output = file('class-count.txt')
timer.end()
Don’t forget to name your root project!
class MyPlug implements Plugin<Project> {
void apply(Project project) {
def plug = project.extensions.create('timer', MyPlugExtension, project)
def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask
countClasses.input = project.file(project.buildDir, 'classes')
}
}
class MyPlugExtension {
Project project
void start() { project.ext.timestamp = System.currentTimeMillis() }
void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") }
}
class CountClassesTask extends DefaultTask {
@InputDirectory File input
@OutputFile File output
@TaskAction
void generateClassCountFile() {
def counter=0
def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor
Files.walkFileTree(input.toPath(),cfv)
output.text = "$counter files"
}
}
implementation-class=com.bar.MyPlug
apply plugin: 'my-plug'
timer.start()
tasks.countClasses.output = file('class-count.txt')
timer.end()
rootProject.name = 'tasks-and-plugins'
But wait! One more thing!
If you do this you can start debugging your builds!
gradlew -Dorg.gradle.debug=true --no-daemon build
● Attach remote debugger on port 5005
● Set breakpoints in your plugins and tasks under buildSrc
● Or Gradle classes that you see from the debug log
● You still cannot set breakpoints in the init scripts and build scritps.
One more reason to keep them declarative.
Keep in mind that Gradle decorates some objects such as tasks and extensions,
The End

Weitere ähnliche Inhalte

Was ist angesagt?

GR8Conf 2011: Grails Webflow
GR8Conf 2011: Grails WebflowGR8Conf 2011: Grails Webflow
GR8Conf 2011: Grails Webflow
GR8Conf
 

Was ist angesagt? (20)

Gwt RPC
Gwt RPCGwt RPC
Gwt RPC
 
Angular mix chrisnoring
Angular mix chrisnoringAngular mix chrisnoring
Angular mix chrisnoring
 
The world of gradle - an introduction for developers
The world of gradle  - an introduction for developersThe world of gradle  - an introduction for developers
The world of gradle - an introduction for developers
 
Typescript barcelona
Typescript barcelonaTypescript barcelona
Typescript barcelona
 
Gradle For Beginners (Serbian Developer Conference 2013 english)
Gradle For Beginners (Serbian Developer Conference 2013 english)Gradle For Beginners (Serbian Developer Conference 2013 english)
Gradle For Beginners (Serbian Developer Conference 2013 english)
 
Grails transactions
Grails   transactionsGrails   transactions
Grails transactions
 
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
 
Javascript Promises/Q Library
Javascript Promises/Q LibraryJavascript Promises/Q Library
Javascript Promises/Q Library
 
Durable functions
Durable functionsDurable functions
Durable functions
 
Cool JVM Tools to Help You Test
Cool JVM Tools to Help You TestCool JVM Tools to Help You Test
Cool JVM Tools to Help You Test
 
Reactive programming every day
Reactive programming every dayReactive programming every day
Reactive programming every day
 
GR8Conf 2011: Grails Webflow
GR8Conf 2011: Grails WebflowGR8Conf 2011: Grails Webflow
GR8Conf 2011: Grails Webflow
 
JavaOne 2013: Java 8 - The Good Parts
JavaOne 2013: Java 8 - The Good PartsJavaOne 2013: Java 8 - The Good Parts
JavaOne 2013: Java 8 - The Good Parts
 
Gradle in 45min
Gradle in 45minGradle in 45min
Gradle in 45min
 
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers VersionCool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
 
Architecting Alive Apps
Architecting Alive AppsArchitecting Alive Apps
Architecting Alive Apps
 
Angular for Java Enterprise Developers: Oracle Code One 2018
Angular for Java Enterprise Developers: Oracle Code One 2018Angular for Java Enterprise Developers: Oracle Code One 2018
Angular for Java Enterprise Developers: Oracle Code One 2018
 
Intro
IntroIntro
Intro
 
Azure Durable Functions (2019-03-30)
Azure Durable Functions (2019-03-30) Azure Durable Functions (2019-03-30)
Azure Durable Functions (2019-03-30)
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin Writing
 

Andere mochten auch

ภูมิปัญญาบางกอก.Pptx2
ภูมิปัญญาบางกอก.Pptx2ภูมิปัญญาบางกอก.Pptx2
ภูมิปัญญาบางกอก.Pptx2
mile_sonsung
 
5 taller de recapitulacion
5 taller de recapitulacion5 taller de recapitulacion
5 taller de recapitulacion
cristian guevara
 
Day1 challenges and-concerns-in-tvet-training-assessment-and-certification
Day1 challenges and-concerns-in-tvet-training-assessment-and-certificationDay1 challenges and-concerns-in-tvet-training-assessment-and-certification
Day1 challenges and-concerns-in-tvet-training-assessment-and-certification
yohtna_76
 

Andere mochten auch (18)

Are You Ready to Cut The Cable?
Are You Ready to Cut The Cable?Are You Ready to Cut The Cable?
Are You Ready to Cut The Cable?
 
Trade mark
Trade markTrade mark
Trade mark
 
ภูมิปัญญาบางกอก.Pptx2
ภูมิปัญญาบางกอก.Pptx2ภูมิปัญญาบางกอก.Pptx2
ภูมิปัญญาบางกอก.Pptx2
 
Trevon Wilson Resume
Trevon Wilson ResumeTrevon Wilson Resume
Trevon Wilson Resume
 
Lions koncertai 2002 2012
Lions koncertai 2002 2012Lions koncertai 2002 2012
Lions koncertai 2002 2012
 
Jono Bartkaus prezentacija konferencijoje (2013)
Jono Bartkaus prezentacija konferencijoje (2013)Jono Bartkaus prezentacija konferencijoje (2013)
Jono Bartkaus prezentacija konferencijoje (2013)
 
5 taller de recapitulacion
5 taller de recapitulacion5 taller de recapitulacion
5 taller de recapitulacion
 
Tremtis - mano seimos istorija (Jonas Bartkus)
Tremtis - mano seimos istorija (Jonas Bartkus)Tremtis - mano seimos istorija (Jonas Bartkus)
Tremtis - mano seimos istorija (Jonas Bartkus)
 
E3
E3E3
E3
 
Zoodiacal
ZoodiacalZoodiacal
Zoodiacal
 
Vip
VipVip
Vip
 
Kelione i Sibira
Kelione i Sibira Kelione i Sibira
Kelione i Sibira
 
Atom structure
Atom structureAtom structure
Atom structure
 
Tell me more
Tell me moreTell me more
Tell me more
 
Pagina con maquetacion
Pagina con maquetacionPagina con maquetacion
Pagina con maquetacion
 
Day1 challenges and-concerns-in-tvet-training-assessment-and-certification
Day1 challenges and-concerns-in-tvet-training-assessment-and-certificationDay1 challenges and-concerns-in-tvet-training-assessment-and-certification
Day1 challenges and-concerns-in-tvet-training-assessment-and-certification
 
The history-of-magical-girl-anime-r
The history-of-magical-girl-anime-rThe history-of-magical-girl-anime-r
The history-of-magical-girl-anime-r
 
The Hstory of Magical Girl Anime: Sparkles Without Cullens
The Hstory of Magical Girl Anime: Sparkles Without CullensThe Hstory of Magical Girl Anime: Sparkles Without Cullens
The Hstory of Magical Girl Anime: Sparkles Without Cullens
 

Ähnlich wie Gradle plugins 101

Grails Plugin
Grails PluginGrails Plugin
Grails Plugin
guligala
 

Ähnlich wie Gradle plugins 101 (20)

GradleFX
GradleFXGradleFX
GradleFX
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin Writing
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin Writing
 
Improving your Gradle builds
Improving your Gradle buildsImproving your Gradle builds
Improving your Gradle builds
 
Gradle plugin, take control of the build
Gradle plugin, take control of the buildGradle plugin, take control of the build
Gradle plugin, take control of the build
 
Writing and Publishing Puppet Modules
Writing and Publishing Puppet ModulesWriting and Publishing Puppet Modules
Writing and Publishing Puppet Modules
 
Google App Engine Developer - Day3
Google App Engine Developer - Day3Google App Engine Developer - Day3
Google App Engine Developer - Day3
 
Finding Clojure
Finding ClojureFinding Clojure
Finding Clojure
 
Polyglot automation - QA Fest - 2015
Polyglot automation - QA Fest - 2015Polyglot automation - QA Fest - 2015
Polyglot automation - QA Fest - 2015
 
QA Fest 2015. Яков Крамаренко. Polyglot automation
QA Fest 2015. Яков Крамаренко. Polyglot automation QA Fest 2015. Яков Крамаренко. Polyglot automation
QA Fest 2015. Яков Крамаренко. Polyglot automation
 
Celery
CeleryCelery
Celery
 
Writing and Publishing Puppet Modules - PuppetConf 2014
Writing and Publishing Puppet Modules - PuppetConf 2014Writing and Publishing Puppet Modules - PuppetConf 2014
Writing and Publishing Puppet Modules - PuppetConf 2014
 
Idiomatic gradle plugin writing
Idiomatic gradle plugin writingIdiomatic gradle plugin writing
Idiomatic gradle plugin writing
 
Protractor framework – how to make stable e2e tests for Angular applications
Protractor framework – how to make stable e2e tests for Angular applicationsProtractor framework – how to make stable e2e tests for Angular applications
Protractor framework – how to make stable e2e tests for Angular applications
 
Capstone ms2
Capstone ms2Capstone ms2
Capstone ms2
 
Grails Plugin
Grails PluginGrails Plugin
Grails Plugin
 
Threads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOSThreads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOS
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
 
Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)
 
Angular Schematics
Angular SchematicsAngular Schematics
Angular Schematics
 

Kürzlich hochgeladen

introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 

Kürzlich hochgeladen (20)

Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
How to Choose the Right Laravel Development Partner in New York City_compress...
How to Choose the Right Laravel Development Partner in New York City_compress...How to Choose the Right Laravel Development Partner in New York City_compress...
How to Choose the Right Laravel Development Partner in New York City_compress...
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 

Gradle plugins 101

  • 1. Gradle Plugins 101 Getting up and running @ddimitrov
  • 2. Gradle bootstraps your build extensions If you put some code in a project named buildSrc, directly under the root of your build, Gradle will automatically compile them and add them to the classpath of the main build. This allows you to quickly hack plugins, tasks or utility classes that you use in your build scripts. https://docs.gradle.org/current/userguide/organizing_build_logic.html#sec:build_sources
  • 3. You can put all the code for your plugin in one file class MyPlug implements Plugin<Project> { void apply(Project project) { def plug = project.extensions.create('timer', MyPlugExtension, project) def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask countClasses.input = project.file(project.buildDir, 'classes') } } class MyPlugExtension { Project project void start() { project.ext.timestamp = System.currentTimeMillis() } void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") } } class CountClassesTask extends DefaultTask { @InputDirectory File input @OutputFile File output @TaskAction void generateClassCountFile() { def counter=0 def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor Files.walkFileTree(input.toPath(),cfv) output.text = "$counter files" } } Not necessarily a good idea, but I can and I often do
  • 4. Use extensions to expose plugin level configuration class MyPlug implements Plugin<Project> { void apply(Project project) { def plug = project.extensions.create('timer', MyPlugExtension, project) def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask countClasses.input = project.file(project.buildDir, 'classes') } } class MyPlugExtension { Project project void start() { project.ext.timestamp = System.currentTimeMillis() } void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") } } class CountClassesTask extends DefaultTask { @InputDirectory File input @OutputFile File output @TaskAction void generateClassCountFile() { def counter=0 def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor Files.walkFileTree(input.toPath(),cfv) output.text = "$counter files" } } That means mostly settings. Actually, you can put utility methods too, but better keep them to config phase. P.S. if you are not sure what the pre paragraph means - just do settings.
  • 5. Use tasks to do stuff class MyPlug implements Plugin<Project> { void apply(Project project) { def plug = project.extensions.create('timer', MyPlugExtension, project) def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask countClasses.input = project.file(project.buildDir, 'classes') } } class MyPlugExtension { Project project void start() { project.ext.timestamp = System.currentTimeMillis() } void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") } } class CountClassesTask extends DefaultTask { @InputDirectory File input @OutputFile File output @TaskAction void generateClassCountFile() { def counter=0 def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor Files.walkFileTree(input.toPath(),cfv) output.text = "$counter files" } } BTW, these strings are the names by which the tasks and extensions would appear in your build script when you apply the plugin.
  • 6. Create a property file referring to your plugin class class MyPlug implements Plugin<Project> { void apply(Project project) { def plug = project.extensions.create('timer', MyPlugExtension, project) def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask countClasses.input = project.file(project.buildDir, 'classes') } } class MyPlugExtension { Project project void start() { project.ext.timestamp = System.currentTimeMillis() } void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") } } class CountClassesTask extends DefaultTask { @InputDirectory File input @OutputFile File output @TaskAction void generateClassCountFile() { def counter=0 def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor Files.walkFileTree(input.toPath(),cfv) output.text = "$counter files" } } implementation-class=com.bar.MyPlug
  • 7. Apply the plugin using the name of the props file class MyPlug implements Plugin<Project> { void apply(Project project) { def plug = project.extensions.create('timer', MyPlugExtension, project) def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask countClasses.input = project.file(project.buildDir, 'classes') } } class MyPlugExtension { Project project void start() { project.ext.timestamp = System.currentTimeMillis() } void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") } } class CountClassesTask extends DefaultTask { @InputDirectory File input @OutputFile File output @TaskAction void generateClassCountFile() { def counter=0 def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor Files.walkFileTree(input.toPath(),cfv) output.text = "$counter files" } } implementation-class=com.bar.MyPlug apply plugin: 'my-plug' timer.start() tasks.countClasses.output = file('class-count.txt') timer.end()
  • 8. Your extension and predefined tasks are applied class MyPlug implements Plugin<Project> { void apply(Project project) { def plug = project.extensions.create('timer', MyPlugExtension, project) def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask countClasses.input = project.file(project.buildDir, 'classes') } } class MyPlugExtension { Project project void start() { project.ext.timestamp = System.currentTimeMillis() } void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") } } class CountClassesTask extends DefaultTask { @InputDirectory File input @OutputFile File output @TaskAction void generateClassCountFile() { def counter=0 def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor Files.walkFileTree(input.toPath(),cfv) output.text = "$counter files" } } implementation-class=com.bar.MyPlug apply plugin: 'my-plug' timer.start() tasks.countClasses.output = file('class-count.txt') timer.end()
  • 9. You can call methods and set props on them class MyPlug implements Plugin<Project> { void apply(Project project) { def plug = project.extensions.create('timer', MyPlugExtension, project) def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask countClasses.input = project.file(project.buildDir, 'classes') } } class MyPlugExtension { Project project void start() { project.ext.timestamp = System.currentTimeMillis() } void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") } } class CountClassesTask extends DefaultTask { @InputDirectory File input @OutputFile File output @TaskAction void generateClassCountFile() { def counter=0 def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor Files.walkFileTree(input.toPath(),cfv) output.text = "$counter files" } } implementation-class=com.bar.MyPlug apply plugin: 'my-plug' timer.start() tasks.countClasses.output = file('class-count.txt') timer.end() rootProject.name = 'tasks-and-plugins'
  • 10. So, this is what the build looks like - modular... class MyPlug implements Plugin<Project> { void apply(Project project) { def plug = project.extensions.create('timer', MyPlugExtension, project) def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask countClasses.input = project.file(project.buildDir, 'classes') } } class MyPlugExtension { Project project void start() { project.ext.timestamp = System.currentTimeMillis() } void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") } } class CountClassesTask extends DefaultTask { @InputDirectory File input @OutputFile File output @TaskAction void generateClassCountFile() { def counter=0 def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor Files.walkFileTree(input.toPath(),cfv) output.text = "$counter files" } } implementation-class=com.bar.MyPlug apply plugin: 'my-plug' timer.start() tasks.countClasses.output = file('class-count.txt') timer.end()
  • 11. ...and cohesive class MyPlug implements Plugin<Project> { void apply(Project project) { def plug = project.extensions.create('timer', MyPlugExtension, project) def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask countClasses.input = project.file(project.buildDir, 'classes') } } class MyPlugExtension { Project project void start() { project.ext.timestamp = System.currentTimeMillis() } void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") } } class CountClassesTask extends DefaultTask { @InputDirectory File input @OutputFile File output @TaskAction void generateClassCountFile() { def counter=0 def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor Files.walkFileTree(input.toPath(),cfv) output.text = "$counter files" } } implementation-class=com.bar.MyPlug apply plugin: 'my-plug' timer.start() tasks.countClasses.output = file('class-count.txt') timer.end()
  • 12. Don’t forget to name your root project! class MyPlug implements Plugin<Project> { void apply(Project project) { def plug = project.extensions.create('timer', MyPlugExtension, project) def countClasses = project.task('countClasses', type: CountClassesTask) as CountClassesTask countClasses.input = project.file(project.buildDir, 'classes') } } class MyPlugExtension { Project project void start() { project.ext.timestamp = System.currentTimeMillis() } void end() { project.logger.lifecycle("Time elapsed ${System.currentTimeMillis() - project.timestamp}") } } class CountClassesTask extends DefaultTask { @InputDirectory File input @OutputFile File output @TaskAction void generateClassCountFile() { def counter=0 def cfv = [visitFile: { file, attrs -> counter++ } ].withDefault { file, attrs -> } as FileVisitor Files.walkFileTree(input.toPath(),cfv) output.text = "$counter files" } } implementation-class=com.bar.MyPlug apply plugin: 'my-plug' timer.start() tasks.countClasses.output = file('class-count.txt') timer.end() rootProject.name = 'tasks-and-plugins'
  • 13. But wait! One more thing!
  • 14. If you do this you can start debugging your builds! gradlew -Dorg.gradle.debug=true --no-daemon build ● Attach remote debugger on port 5005 ● Set breakpoints in your plugins and tasks under buildSrc ● Or Gradle classes that you see from the debug log ● You still cannot set breakpoints in the init scripts and build scritps. One more reason to keep them declarative. Keep in mind that Gradle decorates some objects such as tasks and extensions,