-
15. Re: NEW BUILD
adrian.brock Jan 3, 2005 6:58 PM (in response to adrian.brock)Before I go further, the two files can be combined if you just want a standalone
project, e.g.: This file will actually cause my ant classes to build themselves...<?xml version="1.0"?> <!-- JBoss, the OpenSource J2EE webOS Distributable under LGPL license. See terms of license at gnu.org. --> <project name="project" default="build" basedir="." > <!-- Import the types --> <import file="src/resources/tasks.xml"/> <build id="JBossBuild" targetdefs="targets" description="The main build"> <component id="ant"> <artifact id="ant.jar" location="file:///usr/java/apache-ant-1.6.2/lib/ant.jar" /> </component> <component id="jbossbuild"> <artifact id="jbossbuild.jar"/> <artifact id="jbossbuild.api"/> </component> </build> <!-- The component definition --> <componentdef component="jbossbuild" description="JBoss Build"> <source id="main"> <include input="ant.jar"/> </source> <artifactdef artifact="jbossbuild.jar"> <include input="main"/> </artifactdef> <artifactdef artifact="jbossbuild.api"> <include input="main"/> </artifactdef> </componentdef> </project>
-
16. Re: NEW BUILD
adrian.brock Jan 3, 2005 7:05 PM (in response to adrian.brock)Finally we have the tasks.xml where all the magic occurs:
<?xml version="1.0"?> <!-- JBoss, the OpenSource J2EE webOS Distributable under LGPL license. See terms of license at gnu.org. --> <project name="jboss.ant.tasks" default="help" > <!-- PROPERTIES --> <!-- JBoss Tasks Classpath --> <property name="jboss.tasks.path" value="../jbossbuild/output/eclipse-classes/main" /> <!-- TYPEDEFS --> <!-- The build type --> <typedef name="build" classname="org.jboss.ant.types.build.Build" loaderRef="jboss.tasks.path" classpath="${jboss.tasks.path}" /> <!-- The artifact type definition type --> <typedef name="artifacttype" classname="org.jboss.ant.types.build.ArtifactType" loaderRef="jboss.tasks.path" classpath="${jboss.tasks.path}" /> <!-- The component definition type --> <typedef name="componentdef" classname="org.jboss.ant.types.component.ComponentDefinition" loaderRef="jboss.tasks.path" classpath="${jboss.tasks.path}" /> <!-- The includes type --> <typedef name="includes" classname="org.jboss.ant.types.Includes" loaderRef="jboss.tasks.path" classpath="${jboss.tasks.path}" /> <!-- The build targets type --> <typedef name="targets" classname="org.jboss.ant.types.target.TargetDefinitions" loaderRef="jboss.tasks.path" classpath="${jboss.tasks.path}" /> <!-- TASKDEFS --> <!-- Update ide info for the main build --> <taskdef name="idemain" classname="org.jboss.ant.tasks.build.IDETask" loaderRef="jboss.tasks.path" classpath="${jboss.tasks.path}" /> <!-- Update ide info for the component --> <taskdef name="idecomponent" classname="org.jboss.ant.tasks.component.IDETask" loaderRef="jboss.tasks.path" classpath="${jboss.tasks.path}" /> <!-- DEFINITIONS --> <!-- The artifact types --> <artifacttype id="jar" outputtype="lib"/> <artifacttype id="api" outputtype="api"/> <!-- The default targets --> <targets id="targets"> <!-- Build All --> <targetdef target="all" description="Build All"> <main depends="build, doc, test, archives" components="none"/> <component depends="build, doc, test"/> </targetdef> <!-- Build --> <targetdef target="build" description="Build"> <!-- Build the main release --> <main> <mkdir dir="@{releaseDir}"/> <antCall target="release"/> </main> <!-- Build the component --> <component> <mkdir dir="@{output}"/> </component> <!-- Compile the source --> <source> <mkdir dir="@{output}"/> <depend srcdir="@{sourcePath}" destdir="@{output}"> <classpath> <pathelements/> </classpath> </depend> <javac srcdir="@{sourcePath}" destdir="@{output}"> <classpath> <pathelements/> </classpath> </javac> </source> <!-- Create a jar archive --> <jar> <mkdir dir="@{parentDir}"/> <jar destfile="@{output}"> <filesets/> </jar> </jar> </targetdef> <!-- Build the release --> <targetdef target="release"> <!-- Copy the artifact into the release --> <artifact when="@{release}"> <mkdir dir="@{release}"/> <copy todir="@{release}"> <output/> </copy> </artifact> </targetdef> <!-- Build the release archives --> <targetdef target="archives"> <!-- Make the archives --> <main> <!-- Create the zip file --> <zip destfile="@{output}/@{releaseName}.zip" basedir="@{releaseDir}" /> </main> </targetdef> <!-- Documentation --> <targetdef target="doc" description="Documentation"> <!-- Generate the documentation --> <component depends="api"/> </targetdef> <!-- Javadoc --> <targetdef target="api" description="Javadoc"> <!-- Generate the javadoc --> <component/> <api> <mkdir dir="@{output}"/> <javadoc packagenames="*" destdir="@{output}" > <doctitle> <![CDATA[<h1>@{description} API Documentation</h1>]]> </doctitle> <bottom> <![CDATA[ <i> <div align="center"> <font size="-1"> Copyright © 2005 JBoss Inc. All Rights Reservered. </font> </div> </i> ]]> </bottom> <link href="http://java.sun.com/j2se/1.4.2/docs/api/"/> <sourcepath> <sourcepaths/> </sourcepath> <classpath> <sourcepathelements/> </classpath> </javadoc> </api> </targetdef> <!-- Clean the output --> <targetdef target="clean" description="Clean"> <common> <delete dir="@{output}"/> </common> </targetdef> <!-- Clobber everything --> <targetdef target="clobber" description="Clobber"> <main depends="clean"> <delete dir="@{thirdparty}"/> </main> </targetdef> <!-- Synchronize --> <targetdef target="synchronize" description="Synchronize"> <main components="none"> <echo>FIXME cvsupdate ${basedir}</echo> <execant target="synchronize.components"/> <execant target="synchronize.main.after"/> </main> <component> <echo>FIXME cvsupdate ${basedir}</echo> <execant target="synchronize.component.after"/> </component> <artifact local="false"> <echo>FIXME download/cvscheckout</echo> <mkdir dir="@{parentDir}"/> <get src="@{location}" dest="@{output}" useTimestamp="true" verbose="true" /> </artifact> </targetdef> <!-- Commit --> <targetdef target="commit" description="Commit"> <common> <echo>FIXME cvscommit</echo> </common> </targetdef> <!-- Test --> <targetdef target="test" description="Run the Tests"> <component depends="build, runtest"/> </targetdef> <!-- Run the Test --> <targetdef target="runtest"> <component/> <source when="@{test}"> <mkdir dir="@{testDir}"/> <junit fork="true" printSummary="true"> <formatter type="plain"/> <classpath> <pathElements/> </classpath> <batchtest todir="@{testDir}"> <fileset dir="@{sourceDir}" includes="@{test}"/> </batchtest> </junit> </source> </targetdef> </targets> <!-- MACROS --> <!-- The execant macro --> <macrodef name="execant"> <attribute name="dir" default="${basedir}" description="The directory" /> <attribute name="target" description="The target" /> <sequential> <!-- Invoke using a new ant --> <exec dir="@{dir}" executable="ant" > <arg line="@{target}"/> </exec> </sequential> </macrodef> <!-- The invoke macro --> <macrodef name="invoke"> <attribute name="dir" default="${basedir}" description="The directory" /> <attribute name="target" description="The target" /> <sequential> <!-- Invoke using a new ant --> <ant dir="@{dir}" target="@{target}"/> </sequential> </macrodef> <!-- TARGETS --> <target name="rebuild" depends="synchronize" description="Synchronize then build"> <execant target="build"/> </target> <target name="rebuildall" depends="synchronize" description="Synchronize then build all"> <execant target="all"/> </target> <!-- After synchronization processing for the main build --> <target name="synchronize.main.after"> <idemain/> </target> <!-- After synchronization processing for a component --> <target name="synchronize.component.after"> <idecomponent/> </target> <target name="help"> <fail message="Do not execute this build fragment directly!"/> </target> </project>
The elements are as follows:
typedef - this defines the classes that handle the declarations from the other files
taskdef - standard stuff, in this case I have two custom task to generate ide files
for the projects (one for the integration bulld, for the component)
definition - this is an implementation detail. Rather than hardwiring what to do with
each artifact, the artifacttype lets you override parameters like the output directory
targetdef - this is where the real work is done, there are a number of different
target types each inside a targetdef which I will explain in the next post.
macrodef - these are just ant-1.6 macros which are helpers
targets - some common targets that don't need to defined in the targetdefs (but they could be -
17. Re: NEW BUILD
adrian.brock Jan 3, 2005 7:14 PM (in response to adrian.brock)targets/targetdefs
On the main build there was a reference to the targets<build id="JBossAS" ... targetdefs="targets">
This defines a list of targetdefs and what each should do on the different portions
of the build
main - the top level integration build
component - a component project
common - convenience type when main and component are the same
source - source targets, e.g. compilation
artifact - these are per artifact type so you actually see jar and api rather than
artifact
Take a simple example:<!-- Clean the output --> <targetdef target="clean" description="Clean"> <common> <delete dir="@{output}"/> </common> </targetdef>
This says for top level and component builds we delete the output directory
More complicated<!-- Build the release --> <targetdef target="release"> <!-- Copy the artifact into the release --> <artifact when="@{release}"> <mkdir dir="@{release}"/> <copy todir="@{release}"> <output/> </copy> </artifact> </targetdef>
For each artifact that has a release attribute, we copy it to that release location
Probably the most complicated?<!-- Build --> <targetdef target="build" description="Build"> <!-- Build the main release --> <main> <mkdir dir="@{releaseDir}"/> <antCall target="release"/> </main> <!-- Build the component --> <component> <mkdir dir="@{output}"/> </component> <!-- Compile the source --> <source> <mkdir dir="@{output}"/> <depend srcdir="@{sourcePath}" destdir="@{output}"> <classpath> <pathelements/> </classpath> </depend> <javac srcdir="@{sourcePath}" destdir="@{output}"> <classpath> <pathelements/> </classpath> </javac> </source> <!-- Create a jar archive --> <jar> <mkdir dir="@{parentDir}"/> <jar destfile="@{output}"> <filesets/> </jar> </jar> </targetdef>
On the top level build we create the release
The component level is trivial
The source level is just to compile it
The artifact level involves jaring the referenced source classes
The artifact definition<source id="main"> <include input="test1.jar"/> <include input="jboss-common.jar"/> </source> <artifactdef artifact="test2.jar"> <include input="main"/> </artifactdef>
The source has an id main which the jar includes as its input
The targetdef:<jar> <mkdir dir="@{parentDir}"/> <jar destfile="@{output}"> <filesets/> </jar> </jar>
This says take all the files sets that are the input to a jar artifact
Each -
18. Re: NEW BUILD
adrian.brock Jan 3, 2005 7:16 PM (in response to adrian.brock)And this is the kind of targets that get generated:
top level[ejort@htimes2 JBossAS]$ ant -projecthelp Buildfile: build.xml Main targets: all Build All for everything all.components Build All for all the components all.main Build All for the main build only all.test1 Build All for the component test1 all.test2 Build All for the component test2 api Javadoc for everything api.components Javadoc for all the components api.test1 Javadoc for the component test1 api.test2 Javadoc for the component test2 build Build for everything build.components Build for all the components build.main Build for the main build only build.test1 Build for the component test1 build.test2 Build for the component test2 clean Clean for everything clean.components Clean for all the components clean.main Clean for the main build only clean.test1 Clean for the component test1 clean.test2 Clean for the component test2 clobber Clobber for everything clobber.main Clobber for the main build only commit Commit for everything commit.components Commit for all the components commit.main Commit for the main build only commit.test1 Commit for the component test1 commit.test2 Commit for the component test2 doc Documentation for everything doc.components Documentation for all the components doc.test1 Documentation for the component test1 doc.test2 Documentation for the component test2 rebuild Synchronize then build rebuildall Synchronize then build all synchronize Synchronize for everything synchronize.components Synchronize for all the components synchronize.jboss-common.jar Synchronize for the artifact jboss-common.jar synchronize.junit.jar Synchronize for the artifact junit.jar synchronize.main Synchronize for the main build only synchronize.test1 Synchronize for the component test1 synchronize.test2 Synchronize for the component test2 test Run the Tests for everything test.components Run the Tests for all the components test.test1 Run the Tests for the component test1 test.test2 Run the Tests for the component test2 Default target: build
component level[ejort@htimes2 test2]$ ant -projecthelp Buildfile: build.xml Main targets: all Build All api Javadoc api.test2.api Javadoc for the artifact test2.api build Build build.main Build for the source src/main build.test Build for the source src/test build.test2.jar Build for the artifact test2.jar clean Clean commit Commit doc Documentation rebuild Synchronize then build rebuildall Synchronize then build all synchronize Synchronize test Run the Tests Default target: build
-
19. Re: NEW BUILD
adrian.brock Jan 3, 2005 7:23 PM (in response to adrian.brock)A basic critique (broad brush stuff)
PROS of this approach:
1) It is very declartive (though not very human readable)
2) The inputs and outputs are clearly defined and readily available to tools
3) The links between the components/artifacts are clearly defined (you can see what
includes what)
4) The declaritive approach makes the build easy to validate
5) The build files are very small and simple
CONS of this approach
1) It has the same problem as buildmagic in that the process of the build is obfuscated
(although I believe the notions involved can be easily learnt)
2) The idea of an integration build doesn't sit well with the components also being
a standalone project (they directly include the integeration project)<project name="project" default="build" basedir="." > <!-- The main build --> <import file="../JBossAS/build.xml"/>
3) The ant typedef has some limitations which I have been able to workaround
4) Internally it generates ant macros from the typedefs. This is not well defined
in the ant documentation and I may have fallen foul of an undocmented feature. -
20. Re: NEW BUILD
adrian.brock Jan 3, 2005 7:35 PM (in response to adrian.brock)Clarification. The targetdefs contain @ parameters. These are attributes
that come from each typedef,
e.g. test source is identified by a pattern to identify test case classes<source id="test" test="**/*TestCase.java"> <include input="classes"/> <include input="test.path"/> </source>
This is used in the target def for running tests<!-- Run the Test --> <targetdef target="runtest"> <component/> <source when="@{test}"> <mkdir dir="@{testDir}"/> <junit fork="true" printSummary="true"> <formatter type="plain"/> <classpath> <pathElements/> </classpath> <batchtest todir="@{testDir}"> <fileset dir="@{sourceDir}" includes="@{test}"/> </batchtest> </junit> </source> </targetdef>
Most of the attributes have reasonable defaults that can be overriden
integration wide on the build element or for each component/artifact. -
21. Re: NEW BUILD
ryan.campbell Jan 4, 2005 3:41 PM (in response to adrian.brock)"adrian@jboss.org" wrote:
${somedir}/JBossAS - the main integration build
${somedir}/test1 - test1 component
${somedir}/test2 - test2 component
${somedir}/tools - the tools directory containing jboss/tasks.xml
I notice that you declared jboss-common.jar as a dependency of JBossAS, so I assume you see some of the existing components essentially becoming thirdparty libraries of the AS -- being downloaded from the repository along with log4j. At the same time, other components (test1 & test2) are checked out of CVS and compiled from source.
Why the difference? Why not just have all the existing components become external libraries?
If all of the existing components were migrated to standalone projects, they could be integrated into the AS just like any thirdparty library. Their artifacts would be pulled from the repository just like log4j. -
22. Re: NEW BUILD
adrian.brock Jan 4, 2005 4:02 PM (in response to adrian.brock)Hi Ryan,
I don't anticipate that all builds will be standalone.
And certainly developers won't want 20-50 standalone projects that they have to build
separately, update the jars to some location then build the next until you get a final
project.
The idea of the build is that the developer can checkout the projects they want to
work on.
Where they aren't going to modify a project (or use a project under
development) they can just download the binary into thirdparty.
The projects they do want to work on, can be checked out from cvs as
source components.
For the nightly builds, cruise control could checkout all the projects as source
and rebuild the whole thing in one go.
In this example, the project is using the jboss-common.jar as a binary
but test1 and test2 are under development.
If I were to develop it further, I would add a local properties file where the
developer could specify which elements of the project they want as binary
and which they want the source/latest development version.
The default being as now (all components checked out as source). -
23. Re: NEW BUILD
adrian.brock Jan 4, 2005 5:00 PM (in response to adrian.brock)Just to clarify since none of the examples above has it,
it would be something like:<build cvsroot="cvs.sf.net/projects/jboss" tag="Branch_3_2" location="http://www.jboss.org/jboss-3.2/ > ... <component id="common"> cvsmodule="common" location="common" <artifact id="jboss-common.jar"/> </component> ...
Then the developer can choose whether the common module is checked out from
cvs or the artificats downloaded from a "versioned" repository. -
24. Re: NEW BUILD
ryan.campbell Jan 4, 2005 5:17 PM (in response to adrian.brock)"adrian@jboss.org" wrote:
And certainly developers won't want 20-50 standalone projects that they have to build
separately, update the jars to some location then build the next until you get a final
project.
Right, I agree this is not what we want. You shouldn't have to build all standalone projects to build JBAS. Instead, the build script should just download the 20-50 jar files for you."adrian@jboss.org" wrote:
In this example, the project is using the jboss-common.jar as a binary
but test1 and test2 are under development.
Ok, this makes sense. I agree that a developer should be able to check out specific dependencies and use the build artifacts from source rather than the downloaded binaries. -
25. Re: NEW BUILD
pilhuhn Jan 5, 2005 3:39 AM (in response to adrian.brock)And the developer should not only be able to check out a source tree, but also be able to *update* the tree without throwing things away and re-checking out some modules. This not only saves bandwidth, but also time.
-
26. 3710409
adrian.brock Jan 5, 2005 12:05 PM (in response to adrian.brock)"pilhuhn" wrote:
And the developer should not only be able to check out a source tree, but also be able to *update* the tree without throwing things away and re-checking out some modules. This not only saves bandwidth, but also time.
Yes, that is the purpose of the build definition.
If you look at the synchronize method it actually does the following when executed
at the top level.
1) Synchronize the main build project (from cvs)
2) Reinvoke ant to pick up any new build.xml downloaded from cvs
3) Do the same for each component
(including checking out any new components that may have appeared in the build
definition)
With the current JBoss build, any new modules or thirdparty jars requires
the developer to look at CVSROOT/modules
then go to the relevent directory and do a "cvs co"
or blow away the whole thing and check out from scratch. -
27. Re: NEW BUILD
adrian.brock Jan 5, 2005 12:07 PM (in response to adrian.brock)The synchronize also regenerates any ide project files from the build definition
so all you have to do is refresh inside the ide (and maybe import new projects) -
28. Re: NEW BUILD
starksm64 Jan 7, 2005 6:53 PM (in response to adrian.brock)
Max Rydahl Andersen wrote:
> On Thu, 6 Jan 2005 22:41:46 +0100, Christian Bauer
> <christian.bauer@jboss.com> wrote:
>
>> This looks like the right direction, subant and filelist is what we
>> need.
>>
>> I might be intoxicated, but I actually think about using Maven. At
>> least I'd like to have this feature (and it really looks like we all
>> have to use Eclipse to standardize on our own dogfood): Maven can
>> produce Eclipse .project and .classpath files automatically for you
>> and there is a plugin that keeps your Eclipse configuration in sync
>> with them. This would be killer if it includes code style settings
>> etc. as well.
>
>
> Please no! - not Maven ,)
100% agree. I use Maven in my company and my feelings are :
- maven just move the problems
- the idea is cool, the implementation not
- the plugins are not very well standardized
- you'll have to rework some of the default plugins anyway to do what you want (the plugin itself or through a maven.xml file (kind of ant)
>
> If the only need/wish is for shared .project/.classpath then please
> use the ant task that does that instead ! (there is a few of
> these)
+1
>
> But AFAIK these (both the Maven and the Ant based tasks) isn't
> powerfull enough to be usable,( (and I *guess* this also goes for
> intellij)
>
> The generated files will not be able to include refs to the src and
> javadocs of the used .jars, thus I'll loose the ability to step
> through the source code of the external libs.
Actually it's quite easy to fix considering we're using a standardized thirdparty structure and naming convention (i did that for maven)
>
> And that will (in my world atleast) be a serious pain-in-the-* since I
> would then need to recreate those links each time I "accidently"
> runs the build
> and overwriting my .classpath and .project.
Plus, the automatic eclipse3 build don't really like some maven actions
--
Emmanuel Bernard
emmanuel@hibernate.org
callto://emmanuelbernard
http://www.hibernate.org