En trinnvis prosjektbygger er et objekt som manipulerer ressursene i et prosjekt på en bestemt måte. Trinnvise prosjektbyggere brukes ofte på en omdanning av en ressurs for å lage en ressurs eller artefakt av en annen type. Ressurser opprettet av en bygger er typisk merket som avledede ressurser.
Plugin-moduler oppgir trinnvise prosjektbyggere til plattformen for å implementere spesialiserte ressursomdanninger. For eksempel kan Java Development Tools (JDT) definere en trinnvis prosjektbygger som kompilerer en Java-kildefil til en klassefil hver gang en fil legges til eller endres i et Java-prosjekt. Den holder også rede på avhengige filer og kompilerer dem på nytt ved behov.
Fra et programmeringsgrensesnittperspektiv definerer plattformen to grunnleggende typer bygging:
Trinnvise byggere mates med en ressursendringsdelta. Deltaen reflekterer nettoeffekten av alle endringene siden sist byggeren bygde prosjektet. Deltaen likner på den som er brukt i ressursendringshendelser.
Brukeren kan rydde prosjektene periodisk for å tvinge fram en gjenoppbygging av et komplett prosjekt neste gang det utføres en trinnvis bygging i prosjektet. Ved å rydde prosjektet fjernes bygginformasjon, for eksempel problemmerker og klassefiler.
Det er enklest å forstå byggere gjennom å se på eksempler. JDT Java-kompilatoren drives av en trinnvis Java-prosjektbygger som kompilerer filene på nytt, i et prosjekt som påvirkes av endringer. Når en fullstendig bygging utløses (eller en trinnvis bygging etter en rydding), kompileres alle .java-filene i prosjektet. Eventuelle kompileringsproblemer legges til som problemmerker i de berørte .java-filene. Når en trinnvis bygging utløses, kompilerer byggeren selektivt .java-filene som er lagt til, endret eller på annen måte berørt, og som er beskrevet i ressursdeltaen. Problemmerkene oppdateres ved behov. Alle .class-filer eller -merker som ikke lenger er korrekte, fjernes.
Trinnvis bygging har åpenbare ytelsesfordeler for prosjekter med hundre- eller tusenvis av ressurser, de fleste av dem uten å endres på et gitt tidspunkt.
Den tekniske utfordringen for trinnvis bygging består i å finne ut nøyaktig hva som skal bygges på nytt. Den interne tilstanden som vedlikeholdes av Java-byggeren, omfatter for eksempel et avhengighetsdiagram og en liste over rapporterte kompileringsproblemer. Denne informasjonen brukes under en trinnvis bygging for å identifisere hvilke klasser som skal kompileres på nytt, som et svar på en endring i en Java-ressurs.
Selv om den grunnleggende strukturen for bygging er definert i plattformen, utføres selve arbeidet i byggerkoden. Her skal vi ikke komme nærmere inn på mønstre for implementering av komplekse byggere, siden implementeringen avhenger av den bestemte designen i byggeren.
En bygger kan startes eksplisitt på en av følgende måter:
I praksis utløser arbeidsbenkbrukeren en bygging ved å velge kommandoer på ressursnavigatormenyen.
Trinnvise prosjektbyggere kan også startes implisitt av plattformen under en automatisk bygging. Hvis de er aktivert, kjører automatiske byggere hver gang det oppstår endringer i arbeidsområdet.
Utvidelsespunktet org.eclipse.core.resources.builders brukes til å oppgi en trinnvis prosjektbygger til plattformen. Følgende kodetype viser hvordan den hypotetiske plugin-modulen com.example.builders kan bidra med en trinnvis prosjektbygger.
<extension
id="mybuilder" name="My Sample Builder" point="org.eclipse.core.resources.builders">
<builder
<run
class="com.example.builders.BuilderExample">
<parameter name="optimize" value="true" />
<parameter name="comment" value="Builder comment" />
</run>
</builder>
</extension>
Klassen som identifiseres i utvidelsespunktet, må utvide plattformklassen IncrementalProjectBuilder.
public class BuilderExample extends IncrementalProjectBuilder {
IProject[] build(int kind, Map args, IProgressMonitor monitor)
throws CoreException {
// add your build logic here
return null;
}
protected void startupOnInitialize() {
// add builder init logic here
}
protected void clean(IProgressMonitor monitor) {
// add builder clean logic here
}
}
Byggbehandling begynner med metoden build(), som inneholder informasjon om den forespurte byggtypen. Bygget er en av følgende verdier:
Hvis det er forespurt en trinnvis bygging, oppgis en ressursdelta for å beskrive endringene i ressursene siden siste bygging. Følgende snutt raffinerer metoden build().
protected IProject[] build(int kind, Map args, IProgressMonitor monitor
throws CoreException {
if (kind == IncrementalProjectBuilder.FULL_BUILD) {
fullBuild(monitor);
} else {
IResourceDelta delta = getDelta(getProject());
if (delta == null) {
fullBuild(monitor);
} else {
incrementalBuild(delta, monitor);
}
}
return null;
}
Det kan hende at byggeren under byggingen av prosjekt "X", trenger informasjon om endringer i et annet prosjekt, "Y". (For eksempel hvis en Java-klasse i X implementerer et grensesnitt som er oppgitt i Y.) Under byggingen av X er delta for Y tilgjengelig ved å kalle getDelta(Y). For å sikre at plattformen kan oppgi slike deltaer, må X ha en bygger som har deklarert avhengigheten mellom X og Y ved å returnere en matrise som inneholder Y fra et tidligere kall av build(). Hvis en bygger ikke har avhengigheter, kan null returneres. Du finner mer informasjon i IncrementalProjectBuilder.
Logikken som kreves for å behandle en fullstendig bygging, er spesifikk for plugin-modulen. Den kan omfatte besøk i alle prosjektets ressurser eller undersøke andre prosjekter for å finne ut om det er avhengigheter mellom prosjekter. Nedenfor ser du et eksempel på en snutt for implementering av fullstendig bygging.
protected void fullBuild(final IProgressMonitor monitor) throws CoreException {
try {
getProject().accept(new MyBuildVisitor());
} catch (CoreException e) { }
}
Den besøkende utfører byggingen for den spesifikke ressursen (og svarer "true" til videre besøk av alle de underordnede ressursene).
class MyBuildVisitor implements IResourceVisitor {
public boolean visit(IResource res) {
//build the specified resource.
//return true to continue visiting children.
return true;
}
}
Besøksprosessen fortsetter til hele ressurstreet er besøkt.
Når det utføres en trinnvis bygging, arbeider byggeren med en ressursendringsdelta i stedet for et komplett ressurstre.
protected void incrementalBuild(IResourceDelta delta,
IProgressMonitor monitor) throws CoreException {
// the visitor does the work.
delta.accept(new MyBuildDeltaVisitor());
}
Besøksprosessen fortsetter til hele ressursdeltatreet er besøkt. Den spesifikke typen endringer likner på den som er beskrevet i Implementere en ressursendringslytter. En vesentlig forskjell er at du med trinnvise prosjektbyggere arbeider med en ressursdelta basert på et bestemt prosjekt, ikke hele arbeidsområdet.
Arbeidsbenken gjør det mulig for brukere å rydde et prosjekt eller sett med prosjekter før de starter en bygging. Med denne funksjonen kan brukere tvinge en gjenoppbygging fra grunnen av bare i bestemte prosjekter. Byggere bør implementere denne metoden til å rydde opp eventuelle problemmerker og avledede ressurser i prosjektet.
Hvis du vil gjøre en bygger tilgjengelig for et bestemt prosjekt, må den tas med i byggspesifikasjonene for prosjektet. Byggspesifikasjonene for et prosjekt er en liste over kommandoer som skal kjøres når prosjektet bygges, i oppgitt rekkefølge. Hver kommando navngir en enkel trinnvis prosjektbygger.
MERK: Byggernavnet i en byggekommando er den fullt kvalifiserte IDen for byggerutvidelsen. Den fullt kvalifiserte IDen for en utvidelse opprettes ved å kombinere plugin-modulens ID med den enkle utvidelse-IDen i filen plugin.xml. For eksempel har en bygger med den enkle utvidelse-IDen "mybuilder" i plugin-modulen "com.example.builders", navnet "com.example.builders.mybuilder".
Følgende snutt legger til en ny bygger som den første byggeren i den eksisterende listen over byggere.
final String BUILDER_ID = "com.example.builders.mybuilder";
IProjectDescription desc = project.getDescription();
ICommand[] commands = desc.getBuildSpec();
boolean found = false;
for (int i = 0; i < commands.length; ++i) {
if (commands[i].getBuilderName().equals(BUILDER_ID)) {
found = true;
break;
}
}
if (!found) {
//add builder to project
ICommand command = desc.newCommand();
command.setBuilderName(BUILDER_ID);
ICommand[] newCommands = new ICommand[commands.length + 1];
// Add it before other builders.
System.arraycopy(commands, 0, newCommands, 1, commands.length);
newCommands[0] = command;
desc.setBuildSpec(newCommands);
project.setDescription(desc, null);
}
Byggeren for et prosjekt konfigureres bare en gang, vanligvis når prosjektet opprettes. En vanlig måte å knytte en bygger til et prosjekt på er å konfigurere en prosjektnatur.