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.