import javax.swing.*
import java.awt.Dimension
apply plugin: 'idea'
apply plugin: 'eclipse'
defaultTasks 'showGui'
allprojects {
project.ext.jQueryRepo = {
repositories.ivy {
url "http://code.jquery.com"
layout "pattern", {
artifact "[module]-[revision](.[classifier]).[ext]"
}
}
}
project.ext.jQueryUIRepo = {
repositories.ivy {
url "http://code.jquery.com/ui"
layout "pattern", {
artifact "[revision]/[module](.[classifier]).[ext]"
}
}
}
}
project.convention.plugins.addoninfo = new AddOnInfo()
project.convention.plugins.addoninfo.addExtension('providers', new ProviderExtension())
ext.addonInfoFile = file("$buildDir/tmp/addon/info.xml")
task generateAddOnInfo {
afterEvaluate {
inputs.properties project.convention.plugins.addoninfo.properties
outputs.file addonInfoFile
}
doLast {
def text = new StringWriter()
new groovy.xml.MarkupBuilder(text).extension(version: 1) {
project.convention.plugins.addoninfo.addXml(delegate)
}
addonInfoFile.parentFile.mkdirs()
addonInfoFile.text = text.toString()
}
}
task addon(description: "Produces the .addon file", type: Zip) {
dependsOn generateAddOnInfo
inputs.files addonInfoFile, 'LICENSE.txt'
destinationDir = file("$buildDir/libs")
baseName = project.name.toLowerCase() // lower-case'ify the addon name to simplify usage in a web browser (which is case-sensitive)
extension = 'addon'
fileMode = 0644
from(addonInfoFile) // include addon-info.xml in binary
from('LICENSE.txt') // include license in binary
// have the build tell you where the archive was put!
doLast {
println "Addon created as ${addon.archivePath}"
}
}
task build(dependsOn: addon)
task clean(type: Delete) { delete buildDir }
// not intended to be used directly. This is the default task for the script. This allows
// the user to "double-click" on 'gradlew' and have the GUI launch.
task showGui(description: 'Starts a graphical user interface for the build') << {
org.gradle.gradleplugin.userinterface.swing.standalone.BlockingApplication.launchAndBlock();
}
// Helper method to get the installation root directory of the server. This method will either
// return whatever is in the 'serverRootDir' property (if it's set) ...
File getServerDir() {
if (!project.ext.has("serverRootDir"))
project.ext.set("serverRootDir", null);
if (project.ext.serverRootDir == null) {
Properties props = new Properties()
File optionsFile = new File('build.options')
if (optionsFile.exists()) {
optionsFile.withReader { props.load(it) }
project.ext.serverRootDir = props.getProperty('serverRootDir')
}
if (project.ext.serverRootDir == null) {
File dir = pickServerDir()
if (dir == null)
throw new Exception("""serverRootDir property (path to webctrl install directory) not set.
Please set the serverRootDir property on the command line (-PserverRootDir=
) or in the userHome/.gradle/gradle.properties file.""")
project.ext.serverRootDir = dir.absolutePath.replaceAll('\\\\', '/')
props.setProperty('serverRootDir', project.ext.serverRootDir)
optionsFile.withWriter { props.store(it, null) }
}
}
return new File(project.ext.serverRootDir)
}
project.ext.set("getServerDir", {getServerDir()});
// Helper methods to get the directory in which to deploy webapps (add-ons).
ext.getDeployLoc = { new File(getServerDir(), 'addons/'+addon.baseName.toLowerCase()) }
// task that deletes the .war (and exploded dir) from the webserver
task cleanDeploy(description: 'Deletes the war from the webserver', overwrite: true, type:Delete)
cleanDeploy.doFirst { delete deploy.destDir }
// task that builds and deploys the .war to the webserver
task deploy(description: 'Deploys the war to the webserver', type: Sync, dependsOn:generateAddOnInfo) {
ext.destDir = getDeployLoc()
doFirst {
println "Deploying $addon.baseName to ${ext.destDir.canonicalPath}"
}
with addon
into { ext.destDir }
fileMode = 0644
}
// if needed, specify a special repo for the keystore
if (hasProperty('addon_sign_repo')) {
repositories { maven { url addon_sign_repo } }
}
// Allows add-on to request signing. Only works for official add-ons.
ext.signAddon = {
// cannot sign jars with duplicate files, so make sure that doesn't happen
addon {
duplicatesStrategy = "exclude"
}
// add a task to perform the actual signing
def requiredSigningProperties = ['addon_sign_keystore_gav', 'addon_sign_alias', 'addon_sign_password', 'addon_sign_keypass']
task signArchive(description: 'Signs the add-on archive', dependsOn: addon) << {
if (!requiredSigningProperties.every { project.hasProperty(it) })
{
println "All signing properties not defined, the built add-on will not be signed."
println "The required prooperties are:"
requiredSigningProperties.each { println " "+it }
}
else
{
def keyDep = dependencies.create(addon_sign_keystore_gav)
def keystore = configurations.detachedConfiguration(keyDep).resolve().iterator().next()
ant.signjar(jar: war.archivePath, alias:addon_sign_alias, storepass:addon_sign_password, keystore:keystore.path, keypass:addon_sign_keypass)
}
}
// hook in the signArchive task to occur whenever a build is performed
project.afterEvaluate {
tasks['build'].dependsOn signArchive
}
// if signing, allow the add-on to specify it's own licensing requirements (including none). The server
// will only honor this data if the add-on is signed with the valid private key.
project.convention.plugins.addoninfo.addExtension('licenseRequirements', new LicenseRequirementsExtension())
}
File pickServerDir() {
def serverDir = null;
def builder = new groovy.swing.SwingBuilder()
builder.registerBeanFactory('folderChooser', com.jidesoft.swing.FolderChooser)
builder.build {
frame(id: 'mainframe', title:'Pick Server Root Dir', defaultCloseOperation:JFrame.EXIT_ON_CLOSE, size:[440,440], locationRelativeTo: null, show: true) {
panel(border: emptyBorder(10)) {
boxLayout axis: BoxLayout.Y_AXIS
panel {
boxLayout axis: BoxLayout.X_AXIS
label text: 'In order to deploy the add-on to the server (and to run some tests), the build needs to know where the root directory of the server is located.'
}
rigidArea size: new Dimension(0, 10)
panel {
boxLayout axis: BoxLayout.Y_AXIS
panel {
boxLayout axis: BoxLayout.X_AXIS
label text: 'Server root dir:'
hglue()
}
rigidArea size: new Dimension(0, 5)
panel {
boxLayout axis: BoxLayout.X_AXIS
folderChooser id: 'driverDirChooser', currentDirectory: new File('.'), navigationFieldVisible: false, controlButtonsAreShown: false, availableButtons: 0, recentListVisible: false
hglue()
}
}
rigidArea size: new Dimension(0, 10)
panel {
boxLayout axis: BoxLayout.X_AXIS
hglue()
button text: 'Accept', actionPerformed: {
serverDir = builder.driverDirChooser.selectedFolder
dispose()
}
hglue()
button text: 'Cancel', actionPerformed: {
dispose()
}
hglue()
}
}
}
}
// block until the gui is closed
while (builder.mainframe.isVisible()) {
Thread.sleep(100)
}
if (serverDir == null)
throw new GradleException("ERROR: Build cannot continue because the root directory of the server was not specified")
return serverDir
}
idea {
project {
ipr.withXml {
def node = it.asNode()
def vcsConfig = node.component.find { it.'@name' == 'VcsDirectoryMappings' }
vcsConfig.mapping[0].'@vcs' = 'Git'
}
}
}
buildscript {
repositories { maven { url 'http://download.java.net/maven/2/' } }
dependencies { classpath group: 'com.jidesoft', name: 'jide-oss', version: '2.9.0' }
}
// Support for info.xml
class AddOnInfo {
def String name
def String description
def String version
def String vendor
Map extensions = [:]
void info(Closure c) {
c.setDelegate(this)
c.setResolveStrategy Closure.DELEGATE_ONLY
c()
}
def addExtension(name, obj) {
extensions.put(name, obj)
}
// for backwards compatibility
def propertyMissing(String name, value) {
if (name == 'systemMenuProvider')
extensions.get('providers')?.systemMenu = value
else
throw new MissingPropertyException(name)
}
def methodMissing(String name, args) {
if (args[0] instanceof Closure)
{
def ext = extensions.get(name)
if (ext) {
args[0].setDelegate(ext)
args[0].setResolveStrategy Closure.DELEGATE_ONLY
return args[0].call()
}
}
throw new MissingMethodException(name, delegate, args)
}
Map getProperties() {
[ name:name, description:description, version:version, vendor:vendor,
extensions:extensions.collectEntries { key, value -> [(key) : value.getProperties()] }
]
}
private Map getPropMap() {
def map = [:]
if (name)
map['name'] = name
if (description)
map['description'] = description
if (version)
map['version'] = version
if (vendor)
map['vendor'] = vendor
return map
}
void addXml(root) {
propMap.each { key, value ->
root."$key" { root.mkp.yield(value) }
}
extensions.values().each { it.addXml(root) }
}
}
// support for providers in info.xml
class ProviderExtension {
Map providers = [:]
String propNameToXmlElementName(String propName)
{
// this converts a camelCase string to dash-separated all lower case string (i.e. camel-case)
propName.replaceAll('[A-Z]', { '-'+it.toLowerCase() }) + '-provider'
}
def propertyMissing(name, value) { providers.put(name, value); }
Map getProperties() { return providers; }
void addXml(root) {
providers.each { key, value ->
root."${propNameToXmlElementName(key)}" { root.mkp.yield(value) }
}
}
}
// support for license requirements in info.xml (only available if signing is requested
class LicenseRequirementsExtension {
List features = []
Closure markup = {}
Map getProperties() { return [features:features]; }
void addXml(root) {
root.'license-requirements' {
features.each { str -> feature { mkp.yield(str) } }
markup.delegate = root
markup();
}
}
}