diff --git a/AbstractAntCeylonTask.groovy b/AbstractAntCeylonTask.groovy new file mode 100644 index 0000000..e2d977f --- /dev/null +++ b/AbstractAntCeylonTask.groovy @@ -0,0 +1,39 @@ +import org.gradle.api.DefaultTask +import org.gradle.api.file.FileCollection +import org.gradle.api.tasks.TaskAction + +abstract class AbstractAntCeylonTask extends DefaultTask { + + boolean fork = true + + void classpath(Object... cp) { + antClasspath.addAll( cp as List ) + } + + protected String loadAntTask() { + this.ant.typedef( + format : 'xml', + resource : 'org/eclipse/ceylon/ant/antlib.xml', + classpath : project.files(antClasspath).asPath + ) + } + + protected runAntTask( final Map props = [:], final String ceylonTaskName ) { + this.ant."ceylon-${ceylonTaskName}" (props + [ fork : fork ]) + } + + protected runAntTask( final Map props = [:], final String ceylonTaskName, Closure cfg ) { + this.ant."ceylon-${ceylonTaskName}" (props + [ fork : fork ],cfg) + } + + abstract protected void setupAndRunAntTask() + + @TaskAction + void exec() { + loadAntTask() + setupAndRunAntTask() + } + + private List antClasspath = [] + +} diff --git a/AbstractCeylonOsgiArchiveTaskExtension.groovy b/AbstractCeylonOsgiArchiveTaskExtension.groovy new file mode 100644 index 0000000..3f34c10 --- /dev/null +++ b/AbstractCeylonOsgiArchiveTaskExtension.groovy @@ -0,0 +1,167 @@ +import groovy.util.slurpersupport.GPathResult +import org.gradle.api.GradleException +import org.gradle.api.tasks.bundling.AbstractArchiveTask +import org.gradle.api.tasks.bundling.Jar +import org.gradle.util.GradleVersion +import org.eclipse.ceylon.model.loader.OsgiVersion + +/** + * @author Schalk W. Cronjé + */ +abstract class AbstractCeylonOsgiArchiveTaskExtension { + + abstract void configureManifestForTask() + + /** Set to true if javax.lang.model.* needs to be imported + * + */ + boolean importJavaxModel = false + + /** Sets the location of the {@code module.xml} file in a lazy-evaluatable manner + * + * @param location Any location that can be resolve by Gradle's {@code project.file} method. + * + */ + void setModuleLocation(def location) { + this.moduleLocation = location + } + + /** Returns the location of the {@code module.xml} file + * + * @return + */ + File getModuleLocation() { + if(this.moduleLocation == null) { + throw new GradleException('moduleLocation cannot be null') + } + archiveTask.project.file(this.moduleLocation) + } + + /** Gets the {@code mpdule.xml} as traversable tree + * + * @return + */ + GPathResult getModuleContent() { + new XmlSlurper().parse(getModuleLocation()) + } + + /** If module names matches any of these, then {@code resolution:=optional} will be added + * to a {@code Require-Bundle} irrespective of whether the module is marked optioonal or not + * @param moduleNames + */ + void forceOptionalResolutionFor(String... moduleNames) { + optionalResolution.addAll(moduleNames as List) + } + + /** Get list of excluded modules + * + * @return + */ + List getExcludedModuleNames() { + this.excludedModuleNames + } + + /** Add addition modules to be excluded + * + * @param names + */ + void excludedModuleNames(String... names) { + this.excludedModuleNames.addAll(names as List) + } + + /** Override the existing list of excluded module names with a new list. + * + * @param newModuleNames + */ + void setExcludedModuleNames(final List newModuleNames) { + this.excludedModuleNames.clear() + this.excludedModuleNames.addAll(newModuleNames) + } + + String getRequireBundle() { + List optRes = this.optionalResolution + moduleContent.dependencies.module.findAll { module -> + !(excludedModuleNames.contains(module.@name.toString())) + }.collect { module -> + String depOsgiVersion; + if (module.@name.toString().contains("ceylon")) { + depOsgiVersion = OsgiVersion.fromCeylonVersion(module.@slot.toString()); + } else { + depOsgiVersion = module.@slot; + } + String attr = "${module.@name};bundle-version=${depOsgiVersion}" + if(module.@export == 'true') { + attr+=";visibility:=reexport" + } + if(module.@optional== 'true' || optRes.contains(module.@name.toString()) ) { + attr+=";resolution:=optional" + } + attr + }.join(',') + + } + + protected AbstractCeylonOsgiArchiveTaskExtension(AbstractArchiveTask task) { + this.archiveTask = task + } + + protected Map getManifestInstructions( + final String osgiBundleVersion, + final String osgiBundleSymbolicName, + final String exportedBundleVersion, + final Map osgiDynamicImports = [:] + ) { + Map instructions = [ + 'Bundle-SymbolicName' : osgiBundleSymbolicName, + 'Bundle-Version' : osgiBundleVersion, + 'Export-Package' : "!about.html, !licenses, !settings.xml, *;version=\"${exportedBundleVersion}\"", + 'Require-Bundle' : getRequireBundle() + ] as LinkedHashMap + + if(osgiDynamicImports.size()) { + String packages = osgiDynamicImports.collect { k,v -> + k + ';bundle-version=' + v + }.join(',') + instructions+= [ 'DynamicImport-Package' : packages ] + } + + if(importJavaxModel) { + instructions+= ['Import-Package' : 'javax.lang.model.*'] + } else { + instructions+= ['-removeheaders' : 'Import-Package' ] + } + + instructions+= [ + '-nouses' : 'true', + 'Gradle-Version' : GradleVersion.current().toString(), + 'DSTAMP' : TimeStamp.DSTAMP, + 'NOW' : TimeStamp.NOW, + 'TODAY' : TimeStamp.TODAY, + 'TSTAMP' : TimeStamp.TSTAMP + ] + + instructions + } + + protected AbstractArchiveTask getArchiveTask() { + this.archiveTask + } + + private def moduleLocation + private List optionalResolution = [] + private List excludedModuleNames = [ + 'java.base','java.compiler','java.logging', + 'javax.xml','java.instrument', + 'javax.jaxws','java.desktop', + 'java.prefs','oracle.jdk.base', + 'java.jdbc', + 'javax.script', + 'java.auth.kerberos', + 'java.tls', + 'java.management', + 'irg.sl4j.simple' + ] + + private final AbstractArchiveTask archiveTask + +} diff --git a/AntCeylonImportJarTask.groovy b/AntCeylonImportJarTask.groovy new file mode 100644 index 0000000..07f4f11 --- /dev/null +++ b/AntCeylonImportJarTask.groovy @@ -0,0 +1,94 @@ +import org.gradle.api.DefaultTask +import org.gradle.api.file.FileCollection +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.OutputFiles +import org.gradle.api.tasks.TaskAction + +class AntCeylonImportJarTask extends AbstractAntCeylonTask { + + /** Matches {@code force} parameter on Ant task. + * + */ + @Input + boolean force = true + + /** Matches {@code module} parameter on Ant task. + * + */ + @Input + String module + + /** Matches {@code descriptor} parameter on Ant task. + * + */ + @Optional + File getDescriptor() { + this.descriptor ? project.file(this.descriptor) : null + } + + void setDescriptor(def desc) { + this.descriptor = desc + } + + /** Matches {@code jar} parameter on Ant task. + * + */ + @InputFile + File getJarFile() { + project.file(this.jar) + } + + void setJarFile(def jarFile) { + this.jar = jarFile + } + + /** Matches {@code out} parameter on Ant task. + * + */ + @OutputDirectory + File getDestinationDir() { + project.file(this.destinationDir) + } + + void setDestinationDir(def dest) { + this.destinationDir = dest + } + + @OutputFiles + FileCollection outputFiles() { + List mod = getModule().split('/',2) + String prefix = "${destinationDir}/${mod[0].replace('.','/')}/${mod[1]}" + List fileNames = [ + "${prefix}/${getJarFile().name}", + "${prefix}/${getJarFile().name}.sha1" + ] + if(this.descriptor) { + fileNames+= [ + "${prefix}/${getDescriptor().name}", + "${prefix}/${getDescriptor()/name}.sha1" + ] + } + project.files(fileNames) + } + + protected void setupAndRunAntTask() { + Map params = [ + module : getModule(), + jar : getJarFile().absolutePath, + out : getDestinationDir().absolutePath, + force : getForce(), + ] + if(this.descriptor) { + params+= [ descriptor : getDescriptor().absolutePath ] + } + runAntTask params,'import-jar' + } + + private Object jar + private Object destinationDir + private Object descriptor + +} \ No newline at end of file diff --git a/AntCeylonP2Task.groovy b/AntCeylonP2Task.groovy new file mode 100644 index 0000000..70a69f1 --- /dev/null +++ b/AntCeylonP2Task.groovy @@ -0,0 +1,84 @@ +import org.gradle.api.file.FileCollection +import org.gradle.api.tasks.* + +class AntCeylonP2Task extends AbstractAntCeylonTask { + + /** Matches {@code sysRep} parameter on Ant task. + * + */ + @InputDirectory + File getSysRepo() { + project.file(this.sysRepo) + } + + void setSysRepo(def repoDir) { + this.sysRepo = repoDir + } + + /** Matches {@code out} parameter on Ant task. + * + */ + @OutputDirectory + File getDestinationDir() { + project.file(this.destinationDir) + } + + void setDestinationDir(def dest) { + this.destinationDir = dest + } + + /** Matches {@code repositoryName} parameter on Ant task. + * + */ + @Input + String repositoryName + + /** Matches {@code categoryPrefix} parameter on Ant task. + * + */ + @Input + String categoryPrefix + + /** Matches {@code categories} parameter on Ant task. + * + */ + @InputFile + File getCategoriesFile() { + project.file(this.categoriesFile) + } + + void setCategoriesFile(def catXml) { + this.categoriesFile = catXml + } + + void addModule( final String modName, final String modVer) { + modules += [ name : modName, version : modVer ] + } + + @Input + String getModuleListing() { + modules.toString() + } + + + protected void setupAndRunAntTask() { + Map params = [ + sysRep : getSysRepo().absolutePath, + out : getDestinationDir().absolutePath, + repositoryName : getRepositoryName(), + categoryPrefix : getCategoryPrefix(), + categories : getCategoriesFile() + ] + runAntTask params,'p2', { List< Map > m -> + m.each { Map entry -> + module entry + } + }.curry(this.modules) + } + + private Object sysRepo + private Object destinationDir + private Object categoriesFile + private List< Map > modules = [] + +} \ No newline at end of file diff --git a/CeylonAntlr.groovy b/CeylonAntlr.groovy new file mode 100644 index 0000000..2a0256f --- /dev/null +++ b/CeylonAntlr.groovy @@ -0,0 +1,76 @@ +import org.gradle.api.DefaultTask +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction + +// This has been written because Gradle's Antlr plugin is broken. It is +// based upon an idea from Mike Meesson (https://discuss.gradle.org/t/gradle-2-7-2-8-causing-antlr-panic-cannot-find-importvocab-file/11709). +// It is not a fully flexible plugin, but it is sufficient for purposes of +// building Ceylon. +class CeylonAntlr implements Plugin { + void apply(Project project) { + project.with { + apply plugin : 'java' + configurations.maybeCreate 'antlr' + CeylonAntlr.Generate genTask = tasks.create 'generateGrammarSource',CeylonAntlr.Generate + genTask.group = 'Build' + genTask.description = 'Generate source code from ANTLR grammar' + tasks.getByName('compileJava').dependsOn genTask + } + } + + static class Generate extends DefaultTask { + + @OutputDirectory + File getDestinationDirectory() { + project.file(outputDir) + } + + void setDestinationDirectory(Object dir) { + outputDir = dir + } + + void antlrGroup( final String relOutPath, Object src) { + this.groups[relOutPath] = src + } + + @Input + Map> getAntlrGroups() { + final String root = project.projectDir.absolutePath + Map> ret = [:] + this.groups.each { String relPath, def inputFiles -> + ret[relPath] = project.files(inputFiles).files.collect { File f -> + CeylonBuildUtil.relativeTo(f,project.projectDir) + } as Set + } + ret + } + + @TaskAction + void exec() { + final String antlrClasspath = project.configurations.antlr.asPath + final File root = destinationDirectory + + antlrGroups.each { String relPath, Set inputFiles -> + File out = new File(root,relPath) + String outPath = CeylonBuildUtil.relativeTo(out,project.projectDir) + out.mkdirs() + project.javaexec { + main 'org.antlr.Tool' + classpath project.configurations.antlr + args '-fo',outPath + args inputFiles + } + } + } + + private def outputDir = {project.file("${project.buildDir}/generated-source/java")} + private Map groups = [:] + + } + +} + + diff --git a/CeylonBuildIdGenerator.groovy b/CeylonBuildIdGenerator.groovy new file mode 100644 index 0000000..4665175 --- /dev/null +++ b/CeylonBuildIdGenerator.groovy @@ -0,0 +1,50 @@ +import org.gradle.api.DefaultTask +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction + +class CeylonBuildIdGenerator extends DefaultTask { + + CeylonBuildIdGenerator() { + this.buildInfo = project.extensions.getByType(CeylonBuildInfoPlugin.BuildInfo) + enabled = this.buildInfo.hasGitRepository || this.buildInfo.providedBuildId != null + + + outputs.upToDateWhen { + if(this.outputFile !=null) { + File out = getOutputFile() + out.exists() && project.extensions.getByType(CeylonBuildInfoPlugin.BuildInfo).revisionInfo == out.text + } else { + false + } + } + } + + /** Returns the output file + * + * @return + */ + @OutputFile + File getOutputFile() { + project.file(this.outputFile) + } + + /** Sets the output file + * + * @param f Anything that be converted to {@code project.file} + */ + void setOutputFile(Object f) { + this.outputFile = f + } + + @TaskAction + void exec() { + String buildid = buildInfo.revisionInfo + + if(buildid) { + getOutputFile().text = buildid + } + } + + private final CeylonBuildInfoPlugin.BuildInfo buildInfo + private def outputFile +} diff --git a/CeylonBuildInfoPlugin.groovy b/CeylonBuildInfoPlugin.groovy new file mode 100644 index 0000000..2092683 --- /dev/null +++ b/CeylonBuildInfoPlugin.groovy @@ -0,0 +1,40 @@ +import org.gradle.api.Plugin +import org.gradle.api.Project + +class CeylonBuildInfoPlugin implements Plugin { + + static final String EXTENSION_NAME = 'ceylonBuildInfo' + void apply(Project project) { + project.extensions.create( EXTENSION_NAME, CeylonBuildInfoPlugin.BuildInfo,project ) + } + + static class BuildInfo { + final boolean hasGitRepository + final String providedBuildId + final Project project + + BuildInfo(Project project) { + hasGitRepository = project.file("${project.rootProject.projectDir}/.git").exists() + providedBuildId = project.properties.buildid?.trim() ?: System.getProperty('buildid')?.trim() + this.project = project + + if(!hasGitRepository && providedBuildId == null) { + project.logger.error "Git repository not found and -Pbuildid / -Dbuilid was not specified." + } + } + + String getRevisionInfo() { + if (hasGitRepository) { + OutputStream os = new ByteArrayOutputStream() + project.exec { + standardOutput = os + commandLine 'git','rev-parse', '--short', 'HEAD' + } + os.toString().trim() + } else { + providedBuildId + } + } + + } +} diff --git a/CeylonBuildModuleXml.groovy b/CeylonBuildModuleXml.groovy new file mode 100644 index 0000000..54c171a --- /dev/null +++ b/CeylonBuildModuleXml.groovy @@ -0,0 +1,55 @@ +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.SkipWhenEmpty +import org.gradle.api.tasks.TaskAction +import org.apache.tools.ant.filters.ReplaceTokens + +class CeylonBuildModuleXml extends DefaultTask { + String version = project.version + + CeylonBuildModuleXml() { + super() + group = 'build' + description = 'Creates a module.xml from a template file' + } + + @InputFile + File getSourceModule() { + project.file(this.sourceModule) + } + + void setSourceModule(Object f) { + this.sourceModule = f + } + + File getDestinationDir() { + project.file(this.destinationDir) + } + + void setDestinationDir(Object dest) { + this.destinationDir = dest + } + + @OutputFile + File getDestinationFile() { + if(this.destinationDir == null) { + throw new GradleException('Destination directory has not been set') + } + new File(getDestinationDir(),'module.xml') + } + + @TaskAction + void exec() { + project.copy { + from getSourceModule() + into getDestinationDir() + rename '.+','module.xml' + filter ReplaceTokens, tokens : [ 'ceylon-version' : this.version ] + } + } + + private Object sourceModule + private Object destinationDir = { "${project.buildDir}/ceylon-module" } +} diff --git a/CeylonBuildOsgiPlugin.groovy b/CeylonBuildOsgiPlugin.groovy new file mode 100644 index 0000000..bef8899 --- /dev/null +++ b/CeylonBuildOsgiPlugin.groovy @@ -0,0 +1,55 @@ +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.bundling.AbstractArchiveTask +import org.gradle.jvm.tasks.Jar + +/** + * @author Schalk W. Cronjé + */ +class CeylonBuildOsgiPlugin implements Plugin { + + static final String EXTENSION_NAME = 'ceylon' + + static void addOsgiTaskExtension(AbstractArchiveTask archiveTask,Class extType) { + def ceylon = archiveTask.extensions.create(EXTENSION_NAME, extType, archiveTask) + archiveTask.doFirst { + ceylon.configureManifestForTask() + } + } + + static void addOsgiArchiveMethod(AbstractArchiveTask archiveTask) { + archiveTask.ext.setAsOsgiArchive = { + archiveTask.manifest = archiveTask.project.osgiManifest () + archiveTask.manifest.classesDir = archiveTask.project.sourceSets.main.output.classesDir + archiveTask.manifest.classpath = archiveTask.project.configurations.getByName("runtime") + addOsgiTaskExtension(archiveTask,CeylonOsgiArchiveTaskExtension) + } + archiveTask.ext.setAsOsgiExternalArchive = { + archiveTask.manifest = archiveTask.project.osgiManifest () + archiveTask.manifest.classpath = archiveTask.project.fileTree('.') {exclude '**'} + addOsgiTaskExtension(archiveTask,CeylonOsgiExternalArchiveTaskExtension) + } + } + + void apply(Project project) { + + project.with { + apply plugin : 'osgi' + + tasks.withType(Jar) { task -> + if(task.name != 'jar') { + CeylonBuildOsgiPlugin.addOsgiArchiveMethod(task) + } else { + CeylonBuildOsgiPlugin.addOsgiTaskExtension(task,CeylonOsgiArchiveTaskExtension) + } + } + tasks.whenTaskAdded { task -> + if(task instanceof Jar) { + CeylonBuildOsgiPlugin.addOsgiArchiveMethod(task) + } + } + + tasks.create 'moduleXml', CeylonBuildModuleXml + } + } +} diff --git a/CeylonBuildUtil.groovy b/CeylonBuildUtil.groovy new file mode 100644 index 0000000..07736eb --- /dev/null +++ b/CeylonBuildUtil.groovy @@ -0,0 +1,8 @@ +/** + * @author Schalk W. Cronjé + */ +class CeylonBuildUtil { + static String relativeTo(final File thisPath,final File toThatPath) { + toThatPath.toPath().relativize( thisPath.toPath() ).toFile().toString() + } +} diff --git a/CeylonCommonBuildProperties.groovy b/CeylonCommonBuildProperties.groovy new file mode 100644 index 0000000..e787171 --- /dev/null +++ b/CeylonCommonBuildProperties.groovy @@ -0,0 +1,27 @@ +import org.gradle.api.GradleException +import org.gradle.api.Plugin +import org.gradle.api.Project + +/** + * @author Schalk W. Cronjé + */ +class CeylonCommonBuildProperties implements Plugin { + void apply(Project project) { + project.with { + apply plugin : 'com.admc.javaPropFile' + + // Everything in common-build.properties will be availabe on the 'cbp' + // property object + project.extensions.create 'cbp', CeylonCommonBuildPropertiesExtension, + propFileLoader.load (file( + "${rootProject.projectDir}/common-build.properties" + ), [ basedir : rootProject.projectDir, + 'sun.boot.class.path' : '' + ]) + + ext.requiresCBP = { String propName -> project.extensions.cbp.requires(propName) } + } + + } + +} diff --git a/CeylonCommonBuildPropertiesExtension.groovy b/CeylonCommonBuildPropertiesExtension.groovy new file mode 100644 index 0000000..15c83f0 --- /dev/null +++ b/CeylonCommonBuildPropertiesExtension.groovy @@ -0,0 +1,18 @@ +import org.gradle.api.GradleException + +class CeylonCommonBuildPropertiesExtension extends TreeMap { + CeylonCommonBuildPropertiesExtension( Map loadedMap ) { + super(loadedMap) + } + + void requires( final String propName ) { + if(!containsKey(propName)) { + throw new GradleException ("${propName} is not defined in common-build.properties") + } + } + + def propertyMissing(final String propName) { + super.get(propName) + } + +} diff --git a/CeylonOsgiArchiveTaskExtension.groovy b/CeylonOsgiArchiveTaskExtension.groovy new file mode 100644 index 0000000..8de583c --- /dev/null +++ b/CeylonOsgiArchiveTaskExtension.groovy @@ -0,0 +1,65 @@ +import org.eclipse.ceylon.model.loader.OsgiVersion +import org.gradle.api.tasks.bundling.AbstractArchiveTask + +/** This extension will be added to each Archive task if + * the {@code makeOsgiArchive()} extensions ies executed within the archive + * configuration (the latter depends on it being added by the {@code CeylonOsgi} + * plugin). + */ +class CeylonOsgiArchiveTaskExtension extends AbstractCeylonOsgiArchiveTaskExtension { + + CeylonOsgiArchiveTaskExtension( AbstractArchiveTask task ) { + super(task) + } + + CeylonOsgiArchiveTaskExtension call( Closure cfg ) { + def config = cfg.clone() + config.delegate = this + config() + this + } + + /** Set the symbolic name for this bundle. + * Affects {@code Bundle-SymbolicName} + */ + String bundleSymbolicName + + /** Sets the bundle version. + * Affects {@code Bundle-Version} and {@code Export-Package} + */ + String bundleVersion + + /** Add packages that needs to be dynamically imported. + * + * @param importMappings A map in the form of {@code PackagePattern : BundleVersion } + */ + void dynamicImports( Map importMappings ) { + this.dynamicImports+= importMappings + } + + /** Get the list of OSGI manifest instructions as a map + * + * @return + */ + Map getManifestInstructions() { + getManifestInstructions( + bundleVersion, + bundleSymbolicName, + bundleVersion, + dynamicImports + ) + } + + @Override + void configureManifestForTask() { + archiveTask.manifest.name = bundleSymbolicName + archiveTask.manifest { + manifestInstructions.each { k,v -> + instructionReplace k,v + } + } + } + + private Map dynamicImports = [:] + +} diff --git a/CeylonOsgiExternalArchiveTaskExtension.groovy b/CeylonOsgiExternalArchiveTaskExtension.groovy new file mode 100644 index 0000000..5aecfa7 --- /dev/null +++ b/CeylonOsgiExternalArchiveTaskExtension.groovy @@ -0,0 +1,105 @@ +import groovy.util.slurpersupport.GPathResult +import org.gradle.api.GradleException +import org.gradle.api.tasks.bundling.AbstractArchiveTask +import org.gradle.util.GradleVersion + +import java.util.jar.Attributes + +class CeylonOsgiExternalArchiveTaskExtension extends AbstractCeylonOsgiArchiveTaskExtension { + + CeylonOsgiExternalArchiveTaskExtension( AbstractArchiveTask task ) { + super(task) + } + + CeylonOsgiExternalArchiveTaskExtension call( Closure cfg ) { + def config = cfg.clone() + config.delegate = this + config() + this + } + + /** If set to {@code true}, new manifest will be created irrespective of whether + * JAR contains a valid OSGI manifest. + */ + boolean forceNewOsgiManifest = false + + /** An postfix to identify external dependencies which make up parts of the Ceylon distribution. + * + */ + String externalBundleQualifier = 'CEYLON-DEPENDENCIES-v0' + + String suggestNewBundleVersion(final String srcBundleVersion) { + switch(srcBundleVersion) { + case ~/^[0-9]+\.[0-9]+\.[0-9]+$/ : + return "${srcBundleVersion}.${externalBundleQualifier}" + break + case ~/^[0-9]+\.[0-9]+$/ : + return "${srcBundleVersion}.0.${externalBundleQualifier}" + break + case ~/^[0-9]+$/ : + return "${srcBundleVersion}.0.0.${externalBundleQualifier}" + break + case ~/^[0-9]+\.[0-9]+\.[0-9]+\.[^.]+$/ : + return "${srcBundleVersion}-${externalBundleQualifier}" + break + default: + throw new GradleException("External dependency (${bundleSymbolicName}) with a non-supported version") + } + + } + + void seedFrom(final File originalJar) { + Map attrs = [:] + originalJar.withInputStream { input -> + Attributes mainAttributes = new java.util.jar.JarInputStream(input).manifest.mainAttributes + mainAttributes.keySet().each { k -> + attrs[k.toString()] = mainAttributes.getValue(k).toString() + } + } + this.seedAttributes.putAll(attrs) + } + + @Override + void configureManifestForTask() { + GPathResult module = moduleContent + String bundleVersion + String newBundleVersion + String bundleSymbolicName = module.@name + boolean hasOsgi = false + + + if(!seedAttributes.empty) { + hasOsgi = seedAttributes['Bundle-Version']?.size() + bundleVersion = seedAttributes['Bundle-Version'] ?: module.@slot + newBundleVersion = suggestNewBundleVersion(bundleVersion) + } + + + if(!hasOsgi || forceNewOsgiManifest) { + Map instructions = getManifestInstructions( + newBundleVersion, + bundleSymbolicName, + bundleVersion ?: module.@slot + ) + Map merged = [:] + merged.putAll(seedAttributes) + merged.putAll(instructions.findAll{!it.key.startsWith('-')}) + merged.remove('Import-Package') + + archiveTask.manifest.attributes merged + instructions.each { k,v -> + if(k.startsWith('-')) { + archiveTask.manifest.instruction(k,v) + } + } + } else { + seedAttributes['Bundle-Version'] = newBundleVersion + archiveTask.manifest.attributes seedAttributes + archiveTask.manifest.instructionReplace 'Gradle-Version', GradleVersion.current().toString() + } + + } + + private final Map seedAttributes = [:] + +} diff --git a/Checksum.groovy b/Checksum.groovy new file mode 100644 index 0000000..a160de8 --- /dev/null +++ b/Checksum.groovy @@ -0,0 +1,41 @@ +import org.gradle.api.DefaultTask +import org.gradle.api.file.FileCollection +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.OutputFiles +import org.gradle.api.tasks.TaskAction +import org.gradle.api.tasks.bundling.AbstractArchiveTask + +class Checksum extends DefaultTask { + + String algorithm = 'sha1' + + void files(FileCollection fc) { + collections+= fc + } + + void archive(AbstractArchiveTask task) { + archiveTasks+= task + } + + @InputFiles + FileCollection getArtifacts() { + project.files(archiveTasks.collect {it.outputs.files}) + project.files(collections) + } + + @OutputFiles + Set getOutputFiles() { + artifacts.files.collect { File f -> + new File("${f}.${algorithm}") + } as Set + } + + @TaskAction + void exec() { + artifacts.files.each { File f -> + ant.checksum file : f.absolutePath, algorithm : algorithm + } + } + + private List archiveTasks = [] + private List collections = [] +} diff --git a/TimeStamp.groovy b/TimeStamp.groovy new file mode 100644 index 0000000..200741c --- /dev/null +++ b/TimeStamp.groovy @@ -0,0 +1,28 @@ +import groovy.transform.CompileStatic +import java.text.SimpleDateFormat +import org.eclipse.ceylon.model.loader.OsgiVersion + +@CompileStatic +class TimeStamp { + static final BUILD_START = new Date() + static final String OSGI_TIMESTAMP = { + SimpleDateFormat df = OsgiVersion.formatter; + return df.format (BUILD_START) + }.call() + static final String DSTAMP = { + SimpleDateFormat df = new SimpleDateFormat ("yyyyMMdd") + return df.format (BUILD_START) + }.call() + static final String NOW = { + SimpleDateFormat df = new SimpleDateFormat ("yyyyMMddHHmm") + return df.format (BUILD_START) + }.call() + static final String TODAY = { + SimpleDateFormat df = new SimpleDateFormat ("MMM dd yyyy") + return df.format (BUILD_START) + }.call() + static final String TSTAMP = { + SimpleDateFormat df = new SimpleDateFormat ("HHmm") + return df.format (BUILD_START) + }.call() +} diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..0036ca0 --- /dev/null +++ b/build.gradle @@ -0,0 +1,30 @@ +repositories { + maven { + url "https://plugins.gradle.org/m2/" + } +} + +dependencies { +} + +ext { + modelSrc = "${rootProject.projectDir}/../model/src" + modelDest = "${buildDir}/copiedSrc" +} + +task copySrc(type : Copy) { + from modelSrc, { + include 'org/eclipse/ceylon/model/loader/OsgiVersion.java' + } + into modelDest +} + +compileGroovy.dependsOn copySrc + +sourceSets { + main { + groovy { + srcDir modelDest + } + } +}