update,
src compilr with this build.xml:
<property file="system/build/build.properties"/>
<property name="javadoc" value="yes"/>
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy">
<classpath>
<fileset dir="com.pmease.quickbuild/lib" includes="*groovy*.jar"/>
</classpath>
</taskdef>
<taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask">
<classpath location="system/build/lib/xmltask.jar"/>
</taskdef>
<target name="stage.plugin">
<mkdir dir="stage/plugins/${pluginDir}"/>
<copy todir="stage/plugins/${pluginDir}">
<fileset dir="${pluginDir}" excludes=".project, .classpath, build.properties, .settings/**,
src/**, bin/**, test/**, test-src/**, test-out/**, testout/**, testbin/**, test-bin/**,
test-result/**, **/*.java, **/*.class"/>
</copy>
<copy todir="stage/classpath/lib" flatten="true">
<fileset dir="stage/plugins/${pluginDir}" includes="**/*.jar"/>
</copy>
</target>
<target name="compile.plugin">
<javac destdir="stage/plugins/${pluginDir}" encoding="UTF-8" debug="on" source="11" target="11" includeAntRuntime="false">
<src path="${pluginDir}/src"/>
<classpath>
<fileset dir="stage/classpath/lib" includes="**/*.jar"/>
<pathelement location="stage/classpath/classes"/>
</classpath>
</javac>
<copy todir="stage/plugins/${pluginDir}">
<fileset dir="${pluginDir}/src" excludes="**/*.java"/>
</copy>
<copy todir="stage/classpath/classes">
<fileset dir="stage/plugins/${pluginDir}" includes="**/*.class"/>
</copy>
</target>
<target name="jar.plugin">
<xmltask source="${pluginDir}/.classpath" dest="stage/plugins/${pluginDir}/.classpath">
<insert path="/classpath">
<![CDATA[
<classpathentry exported="true" kind="lib" path="${pluginId}_${pluginVersion}.jar">
<attributes>
<attribute name="javadoc_location" value="jar:platform:/resource/com.pmease.quickbuild.bootstrap/javadoc.zip!/"/>
</attributes>
</classpathentry>
]]>
</insert>
<remove path="/classpath/classpathentry[@kind='src']"/>
</xmltask>
<groovy>
if (properties["pluginId"] == "com.pmease.quickbuild") {
new AntBuilder().copy(file:"${properties['basedir']}/stage/asset/release",
tofile:"${properties['basedir']}/stage/plugins/com.pmease.quickbuild/com/pmease/quickbuild/release")
}
</groovy>
<jar destfile="stage/plugins/${pluginId}_${pluginVersion}.jar" manifest="stage/plugins/${pluginDir}/META-INF/MANIFEST.MF">
<fileset dir="stage/plugins/${pluginDir}"/>
</jar>
<groovy>
def dir = new File(properties["basedir"], "stage/plugins/${properties['pluginDir']}")
for (int i = 0; i < 10; i++) {
System.gc()
Thread.sleep(1000)
try {
new AntBuilder().delete(dir: dir.absolutePath, includeEmptyDirs: true)
break
} catch (Exception e) {
if (i == 9) throw e
}
}
</groovy>
</target>
<target name="jar.bootstrap">
<replace file="stage/plugins/${pluginDir}/META-INF/MANIFEST.MF" token=".," value="${pluginId}_${pluginVersion}.jar," />
<jar destfile="stage/plugins/${pluginDir}/${pluginId}_${pluginVersion}.jar" manifest="stage/plugins/${pluginDir}/META-INF/MANIFEST.MF">
<fileset dir="stage/plugins/${pluginDir}">
<exclude name="lib/**"/>
<exclude name="javadoc.zip"/>
<exclude name="*.txt"/>
</fileset>
</jar>
<xmltask source="${pluginDir}/.classpath"
dest="stage/plugins/${pluginDir}/.classpath">
<insert path="/classpath">
<![CDATA[
<classpathentry exported="true" kind="lib" path="${pluginDir}/${pluginId}_${pluginVersion}.jar">
<attributes>
<attribute name="javadoc_location" value="jar:platform:/resource/${pluginDir}/javadoc.zip!/"/>
</attributes>
</classpathentry>
]]>
</insert>
<remove path="/classpath/classpathentry[@kind='src']"/>
</xmltask>
<delete dir="stage/plugins/${pluginDir}/com"/>
<delete dir="stage/plugins/${pluginDir}/org"/>
</target>
<target name="assemble.plugins">
<mkdir dir="stage/classpath/lib"/>
<mkdir dir="stage/classpath/classes"/>
<groovy>
def pluginDependencies = new HashMap()
def pluginDirs = new HashMap()
def pluginVersions = new HashMap()
for (each in new File(properties["basedir"]).listFiles()) {
def manifestFile = new File(each, "META-INF/MANIFEST.MF")
if (manifestFile.exists()) {
def attrs
manifestFile.withInputStream {
stream -> attrs = new java.util.jar.Manifest(stream).getMainAttributes()
}
def pluginId = attrs.getValue("Bundle-SymbolicName")
if (pluginId != null)
if (pluginId.trim().length() != 0) {
def pos = pluginId.indexOf(';')
if (pos != -1)
pluginId = pluginId.substring(0, pos)
pluginDirs.put(pluginId, each)
pluginVersions.put(pluginId, attrs.getValue("Bundle-Version"))
def dependencies = new HashSet()
String required = attrs.getValue("Require-Bundle")
if (required != null) {
for (partial in required.split(",")) {
partial = partial.trim()
if (partial.length() == 0)
continue;
pos = partial.indexOf(';')
if (pos != -1)
partial = partial.substring(0, pos).trim()
dependencies.add(partial);
}
}
pluginDependencies.put(pluginId, dependencies)
}
}
}
for (pluginId in pluginDependencies.keySet()) {
for (dependency in pluginDependencies.get(pluginId)) {
if (!pluginDependencies.containsKey(dependency))
throw new RuntimeException("Plugin '" + pluginId + "' requires non-existant plugin '" + dependency + "'.")
}
}
def sortedPlugins = new ArrayList()
def dependencyIds = new HashMap()
for (entry in pluginDependencies.entrySet())
dependencyIds.put(entry.getKey(), new HashSet(entry.getValue()))
while (!dependencyIds.isEmpty()) {
Set leafs = new HashSet()
for (key in dependencyIds.keySet()) {
if (dependencyIds.get(key).isEmpty()) {
leafs.add(key)
sortedPlugins.add(key)
}
}
if (leafs.isEmpty()) {
Set unprocessed = new HashSet()
for (id in dependencyIds.keySet())
unprocessed.add(id);
throw new RuntimeException("Unable to process dependencies: " + unprocessed
+ ". This is either because circular exists in these dependencies, or because "
+ "some of these dependencies depends on non-existent dependencies.")
}
for (key in leafs)
dependencyIds.remove(key)
for (value in dependencyIds.values())
value.removeAll(leafs)
}
for (pluginId in sortedPlugins) {
properties["pluginDir"] = pluginDirs.get(pluginId).name
ant.project.executeTarget("stage.plugin")
if (new File(pluginDirs.get(pluginId), "src").exists())
ant.project.executeTarget("compile.plugin")
properties["pluginId"] = pluginId
properties["pluginVersion"] = pluginVersions.get(pluginId)
if (pluginId != "com.pmease.quickbuild.bootstrap")
if (pluginId != "com.pmease.quickbuild.libs")
ant.project.executeTarget("jar.plugin")
if (pluginId == "com.pmease.quickbuild.bootstrap")
ant.project.executeTarget("jar.bootstrap")
if (pluginId == "com.pmease.quickbuild.equinoxadapter")
properties["equinoxadapterVersion"] = pluginVersions.get(pluginId)
}
</groovy>
<copy file="stage/plugins/com.pmease.quickbuild.equinoxadapter_${equinoxadapterVersion}.jar"
tofile="stage/framework/org.eclipse.osgi_adapter.jar"/>
<delete dir="stage/classpath"/>
<mkdir dir="stage/plugins/site"/>
<touch file="stage/plugins/site/PUT_YOUR_CUSTOM_PLUGINS_HERE"></touch>
</target>
<target name="license">
<delete dir="stage/license"/>
<mkdir dir="stage/license/lib"/>
<copy todir="stage/license/lib">
<fileset dir="com.pmease.quickbuild.bootstrap/lib"
includes="commons-codec*.jar, commons-lang*.jar"/>
</copy>
<mkdir dir="stage/license/classes"/>
<javac destdir="stage/license/classes" debug="on" source="11">
<src path="com.pmease.quickbuild/src"/>
<include name="com/pmease/quickbuild/license/**/*.java"/>
<classpath>
<fileset dir="stage/license/lib" includes="*.jar"/>
</classpath>
</javac>
<jar destfile="stage/license/quickbuild-license.jar">
<fileset dir="stage/license/classes"/>
</jar>
<delete dir="stage/license/classes"/>
<echo message="License jars built successfully under ${basedir}/stage/license"/>
</target>
<target name="stage">
<groovy>
properties['build.date']=new java.util.Date().getTime();
def osname = System.getProperty("os.name").toLowerCase();
if (osname.contains("windows"))
properties['os.family']="windows";
else if (osname.contains("linux"))
properties['os.family']="linux";
else if (osname.contains("mac"))
properties['os.family']='macosx';
else
properties['os.family']='others';
</groovy>
<fail message="QuickBuild can only be built on windows, linux and macosx." unless="os.family"/>
<mkdir dir="stage"/>
<copy todir="stage">
<fileset dir="system" includes="*.txt" excludes="source-*.txt"/>
<filterset>
<filter token="build.version" value="${build.version}"/>
<filter token="docroot" value="${docroot}"/>
</filterset>
</copy>
<mkdir dir="stage/3rdparty-licenses"/>
<copy todir="stage/3rdparty-licenses">
<fileset dir="system/3rdparty-licenses"/>
</copy>
<mkdir dir="stage/logs"/>
<touch file="stage/logs/console.log"/>
<copy todir="stage/bin">
<fileset dir="system/bin" includes="**/*wrapper*"/>
</copy>
<copy tofile="stage/bin/server.bat" file="system/bin/quickbuild.bat">
<filterset>
<filter token="app.name" value="quickbuild"/>
<filter token="app.long.name" value="QuickBuild Server"/>
<filter token="app.description" value="QuickBuild Server"/>
</filterset>
</copy>
<copy tofile="stage/bin/server.sh" file="system/bin/quickbuild.sh">
<filterset>
<filter token="app.name" value="quickbuild"/>
<filter token="app.long.name" value="QuickBuild Server"/>
<filter token="app.description" value="QuickBuild Server"/>
</filterset>
</copy>
<copy todir="stage/asset">
<fileset dir="system/asset"/>
</copy>
<copy todir="stage/framework">
<fileset dir="system/framework"/>
</copy>
<mkdir dir="stage/sampledb"/>
<propertyfile file="stage/asset/release">
<entry key="version" value="${build.version}"/>
<entry key="build" value="${build.number}"/>
<entry key="date" value="${build.date}"/>
<entry key="docroot" value="${docroot}"/>
</propertyfile>
<antcall target="assemble.plugins"/>
<groovy>
wrapper_classpath="";
int index=1;
new File("${properties['basedir']}/stage/plugins/com.pmease.quickbuild.bootstrap").listFiles().each() {
if (it.name.endsWith(".jar")) {
wrapper_classpath += "wrapper.java.classpath." + index + "=../plugins/com.pmease.quickbuild.bootstrap/" + it.name + "\r\n";
index++;
}
}
new File("${properties['basedir']}/stage/plugins/com.pmease.quickbuild.bootstrap/lib").listFiles().each() {
if (it.name.endsWith(".jar")) {
wrapper_classpath += "wrapper.java.classpath." + index + "=../plugins/com.pmease.quickbuild.bootstrap/lib/" + it.name + "\r\n";
index++;
}
}
properties['wrapper.classpath']=wrapper_classpath;
</groovy>
<copy todir="stage/bin">
<fileset dir="system/bin" includes="*.bat, *.sh" excludes="quickbuild.bat, quickbuild.sh"/>
</copy>
<copy todir="stage/conf">
<fileset dir="system/conf"/>
<filterset>
<filter token="app.name" value="quickbuild"/>
<filter token="app.long.name" value="QuickBuild Server"/>
<filter token="app.description" value="QuickBuild Server"/>
<filter token="classpath" value="${wrapper.classpath}"/>
<filter token="initmemory" value="512"/>
<filter token="maxmemory" value="2048"/>
<filter token="docroot" value="${docroot}"/>
</filterset>
</copy>
<chmod dir="stage/bin" perm="+x" includes="**/*.sh, wrapper-*" excludes="*.dll, *.exe"/>
<!-- agent -->
<delete dir="stage/agent"/>
<copy tofile="stage/agent/buildagent/wrapper.conf" file="system/conf/wrapper.conf">
<filterset>
<filter token="app.name" value="buildagent"/>
<filter token="app.long.name" value="QuickBuild Build Agent"/>
<filter token="app.description" value="QuickBuild Build Agent"/>
<filter token="classpath" value="${wrapper.classpath}"/>
<filter token="initmemory" value="256"/>
<filter token="maxmemory" value="2048"/>
</filterset>
</copy>
<copy tofile="stage/agent/useragent/wrapper.conf" file="system/conf/wrapper.conf">
<filterset>
<filter token="app.name" value="useragent"/>
<filter token="app.long.name" value="QuickBuild User Agent"/>
<filter token="app.description" value="QuickBuild User Agent"/>
<filter token="classpath" value="${wrapper.classpath}"/>
<filter token="initmemory" value="256"/>
<filter token="maxmemory" value="1024"/>
</filterset>
</copy>
<copy file="system/bin/config.sh" tofile="stage/agent/config.sh"/>
<copy file="system/bin/config.bat" tofile="stage/agent/config.bat"/>
<copy file="system/bin/quickbuild.sh" tofile="stage/agent/buildagent/agent.sh">
<filterset>
<filter token="app.name" value="buildagent"/>
<filter token="app.long.name" value="QuickBuild Build Agent"/>
<filter token="app.description" value="QuickBuild Build Agent"/>
</filterset>
</copy>
<copy file="system/bin/quickbuild.bat" tofile="stage/agent/buildagent/agent.bat">
<filterset>
<filter token="app.name" value="buildagent"/>
<filter token="app.long.name" value="QuickBuild Build Agent"/>
<filter token="app.description" value="QuickBuild Build Agent"/>
</filterset>
</copy>
<copy file="system/bin/quickbuild.sh" tofile="stage/agent/useragent/agent.sh">
<filterset>
<filter token="app.name" value="useragent"/>
<filter token="app.long.name" value="QuickBuild User Agent"/>
<filter token="app.description" value="QuickBuild User Agent"/>
</filterset>
</copy>
<copy file="system/bin/quickbuild.bat" tofile="stage/agent/useragent/agent.bat">
<filterset>
<filter token="app.name" value="useragent"/>
<filter token="app.long.name" value="QuickBuild User Agent"/>
<filter token="app.description" value="QuickBuild User Agent"/>
</filterset>
</copy>
<!-- dev -->
<copy todir="stage/dev">
<fileset dir="system/dev" excludes="**/samples.*, **/*.class, **/*.txt, **/*.xml"/>
</copy>
<copy todir="stage/dev">
<fileset dir="system/dev" includes="**/*.txt"/>
<filterset>
<filter token="docroot" value="${docroot}"/>
</filterset>
</copy>
<copy todir="stage/dev/plugin/samples">
<fileset dir=".">
<include name="com.example.*/**"/>
<include name="com.pmease.quickbuild.plugin.artifact/**"/>
<include name="com.pmease.quickbuild.plugin.scm.subversion/**"/>
<include name="com.pmease.quickbuild.plugin.authenticator.ldap/**"/>
<include name="com.pmease.quickbuild.plugin.notifier.msn/**"/>
<include name="com.pmease.quickbuild.plugin.builder.ant/**"/>
<include name="com.pmease.quickbuild.plugin.tracker.redmine/**"/>
<include name="com.pmease.quickbuild.plugin.report.boosttest/**"/>
<exclude name="**/bin/**"/>
</fileset>
<fileset dir="system/dev/plugin" includes="*.xml"/>
</copy>
<groovy>
if (properties["javadoc"] == "yes")
ant.project.executeTarget("javadoc");
</groovy>
</target>
<target name="collectsrc.plugin">
<copy todir="stage/dev/plugin/src">
<fileset dir="${plugin.dir}/src" includes="**/*.java"></fileset>
</copy>
</target>
<target name="javadoc">
<mkdir dir="stage/doclets"/>
<javac destdir="stage/doclets" debug="on" source="11">
<src path="com.pmease.quickbuild.doclets/src"/>
<classpath>
<fileset dir="com.pmease.quickbuild.bootstrap" includes="**/*.jar"/>
</classpath>
</javac>
<copy todir="stage/doclets">
<fileset dir="com.pmease.quickbuild.doclets/src" excludes="**/*.java"/>
</copy>
<mkdir dir="stage/dev/plugin/javadoc"/>
<mkdir dir="stage/dev/plugin/src"/>
<groovy>
for (each in new File(properties["basedir"]).listFiles()) {
if (new File(each, "src").exists()) {
properties["plugin.dir"] = each.name
ant.project.executeTarget("collectsrc.plugin")
}
}
</groovy>
<javadoc destdir="stage/dev/plugin/javadoc" source="11" useexternalfile="true" author="true"
version="true" use="false" windowtitle="QuickBuild API" maxmemory="512m">
<doclet name="com.pmease.quickbuild.doclets.standard.Standard">
<path>
<pathelement path="stage/doclets"/>
<fileset dir="com.pmease.quickbuild.bootstrap" includes="**/*.jar"/>
</path>
</doclet>
<doctitle><![CDATA[<h1>QuickBuild</h1>]]></doctitle>
<bottom><![CDATA[<i>Copyright © 2005-2016 PMEase All Rights Reserved.</i>]]></bottom>
<fileset dir="stage/dev/plugin/src">
<include name="**/*.java"/>
<exclude name="com/pmease/quickbuild/license/**"/>
<exclude name="com/pmease/quickbuild/migration/qb1/**"/>
<exclude name="com/pmease/quickbuild/test/**"/>
<exclude name="org/**"/>
</fileset>
<classpath>
<fileset dir="${basedir}" includes="**/*.jar"/>
</classpath>
</javadoc>
<delete dir="stage/doclets"/>
<zip destfile="stage/plugins/com.pmease.quickbuild.bootstrap/javadoc.zip"
basedir="stage/dev/plugin/javadoc"/>
</target>
<target name="package" depends="stage">
<property name="package.name" value="quickbuild-${build.version}"/>
<mkdir dir="package/${package.name}"/>
<copy todir="package/${package.name}">
<fileset dir="stage" excludes="dev/plugin/javadoc/**, dev/plugin/src/**"/>
</copy>
<zip destfile="package/${package.name}.zip">
<zipfileset dir="package" includes="${package.name}/**/*"
excludes="${package.name}/bin/*.sh, ${package.name}/bin/wrapper-*"/>
<zipfileset dir="package"
includes="${package.name}/bin/*.sh, ${package.name}/bin/wrapper-*"
filemode="755"/>
</zip>
<tar destfile="package/${package.name}.tar.gz" compression="gzip">
<zipfileset dir="package" includes="${package.name}/**/*"
excludes="${package.name}/bin/*.sh, ${package.name}/bin/wrapper-*"/>
<zipfileset dir="package"
includes="${package.name}/bin/*.sh, ${package.name}/bin/wrapper-*"
filemode="755"/>
</tar>
</target>
<target name="package.src">
<mkdir dir="package/quickbuild-${build.version}-src"/>
<copy todir="package/quickbuild-${build.version}-src">
<fileset dir="." includes="com.pmease.quickbuild*/**, com.example.promptbean/**, system/**"
excludes="com.pmease.quickbuild*/bin/**, com.example.promptbean/bin/**, system/source-*.txt,
system/dev/restapi/samples/java/.metadata/**, system/dev/restapi/samples/java/samples/bin/**"/>
<fileset dir="system" includes="source-*.txt"/>
</copy>
<zip destfile="package/quickbuild-${build.version}-src.zip">
<zipfileset dir="package" includes="quickbuild-${build.version}-src/**"/>
</zip>
</target>
<target name="clean">
<delete dir="stage"/>
<delete dir="package"/>
</target>
and this command:
$env:ANT_OPTS="--add-opens java.xml/com.sun.org.apache.xpath.internal=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xpath.internal.objects=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xml.internal.dtm=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xml.internal.dtm.ref=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xml.internal.utils=ALL-UNNAMED"; ant -f build.xml
java use:
java -version
java version "21.0.9" 2025-10-21 LTS
Java(TM) SE Runtime Environment (build 21.0.9+7-LTS-338)
Java HotSpot(TM) 64-Bit Server VM (build 21.0.9+7-LTS-338, mixed mode, sharing)