Přírůstkový tvůrce projektů je objekt, který určitým způsobem manipuluje prostředky v projektu. Přírůstkoví tvůrci projektů se často používají k provedení transformace prostředku, aby vznikl prostředek nebo artefakt jiného druhu.
Moduly plug-in přidávají přírůstkové tvůrce projektů k platformě, aby implementovaly specializované transformace prostředků. Například vývojářské nástroje Java (JDT) definují přírůstkového tvůrce projektů, který zkompiluje zdrojový soubor Java do souboru třídy, kdykoli je do projektu Java přidaný nebo v něm upravený soubor. Také sleduje závislé soubory a v případě potřeby je znovu zkompiluje.
Z pohledu API definuje platforma dva základní typy sestavení:
Přírůstková sestavení využívají rozdílová data prostředku. Rozdílová data odrážejí čistý efekt všech změn prostředku od okamžiku, kdy tvůrce naposledy sestavoval daný projekt. Tato rozdílová data jsou podobná rozdílovým datům používaným uvnitř událostí změn prostředků.
Uživatel může projekty periodicky čistit, aby vynutil znovusestavení celého projektu, až bude příště nad daným projektem prováděno přírůstkové sestavení. Vyčištění projektu odebere informace o sestavení, jako např. značkovače problémů a soubory tříd.
Tvůrce nejlépe pochopíme na příkladu. Kompilátor jazyka Java JDT je řízený přírůstkovým tvůrcem projektů Java, který znovu zkompiluje ty soubory v projektu, které jsou zasaženy změnami. Když se spustí úplné sestavení (nebo přírůstkové sestavení po vyčištění), budou zkompilovány všechny soubory .java v daném projektu. Pokud dojde při kompilaci k jakýmkoli problémům, budou přidány jako značkovače problémů k postiženým souborům .java. Když se spustí přírůstkové sestavení, tvůrce selektivně znovu zkompiluje přidané, změněné, nebo jinak zasažené soubory .java, které jsou popsány v rozdílových datech prostředku, a podle potřeby aktualizuje značkovače problémů. Veškeré soubory .class nebo značkovače, které již neodpovídají, jsou odebrány.
Přírůstkové sestavení má evidentní výhody v oblasti výkonu, když dojde na projekty se stovkami či tisíci prostředků, z nichž většina obvykle zůstává beze změny.
Technickým problémem přírůstkového sestavení je přesně určit, co je třeba znovu sestavit. Například interní stav udržovaný tvůrcem Java zahrnuje věci, jako je graf závislostí a seznam hlášených kompilačních problémů. Tyto informace se používají během přírůstkového sestavení pro určení tříd, které je třeba v reakci na změnu nějakého prostředku Java znovu zkompilovat.
Ačkoli je základní struktura sestavení definována platformou, skutečná práce probíhá v kódu tvůrce. Vzory pro implementaci složitých přírůstkových tvůrců jsou nad rámec této debaty, jelikož taková implementace závisí na návrhu konkrétního tvůrce.
Tvůrce je možné vyvolat explicitně jedním z následujících způsobů:
V praxi spustí uživatel pracovní plochy sestavení výběrem odpovídajících příkazů v nabídce navigátora prostředků.
Přírůstkoví tvůrci projektů jsou vyvoláváni také implicitně platformou během automatického sestavení. Pokud jsou aktivní automatická sestavení, spouští se, kdykoli se změní pracovní prostor.
Pro přidání přírůstkového tvůrce projektů k platformě se používá bod rozšíření org.eclipse.core.resources.builders. Následující markup ukazuje, jak může hypotetický plug-in com.example.builders přispět přírůstkovým tvůrcem projektů.
<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>
Třída určená v tomto bodě rozšíření musí rozšiřovat třídu platformy IncrementalProjectBuilder.
public class BuilderExample extends IncrementalProjectBuilder { IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException { // sem přidat svou logiku sestavení return null; } protected void startupOnInitialize() { // sem přidat logiku inicializace tvůrce } protected void clean(IProgressMonitor monitor) { // sem přidat logiku čištění tvůrce } }
Zpracování sestavení začíná metodou build(), která obsahuje informace o vyžadovaném druhu sestavení. Toto sestavení představuje jedna z následujících hodnot:
Pokud je požadováno přírůstkové sestavení, jsou poskytnuta rozdílová data prostředku, popisující změny v daném prostředku od posledního sestavení. Následující úsek dále rozvíjí metodu 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; }
Někdy se stane, že při sestavování projektu "X," potřebuje tvůrce informace o změnách v jiném projektu "Y." (Například pokud nějaká třída Java v X implementuje rozhraní poskytované v Y.) Při sestavování X jsou rozdílová data pro Y dostupná prostřednictvím volání getDelta(Y). Aby platforma dokázala poskytnout taková rozdílová data, musí mít tvůrce X deklarovanou závislost mezi X a Y vrácením pole obsahujícího Y z předchozího volání build(). Pokud tvůrce nemá žádné závislosti, může prostě vrátit hodnotu null. Další informace viz IncrementalProjectBuilder.
Logika potřebná ke zpracování požadavku na úplné sestavení závisí na konkrétním modulu plug-in. Může zahrnovat návštěvu každého prostředku v projektu, či dokonce prozkoumání ostatních projektů, zda jsou mezi projekty nějaké závislosti. Následující úsek kódu navrhuje, jak je možné implementovat úplné sestavení.
protected void fullBuild(final IProgressMonitor monitor) throws CoreException { try { getProject().accept(new MyBuildVisitor()); } catch (CoreException e) { } }
Návštěvník sestavení by provedl sestavení pro daný prostředek (a odpověděl hodnotou true, aby se pokračovalo v návštěvách všech podřízených prostředků).
class MyBuildVisitor implements IResourceVisitor { public boolean visit(IResource res) { //sestavit uvedený prostředek. //vrátit true, aby se pokračovalo v návštěvách podřízených prvků. return true; } }
Proces návštěv pokračuje, dokud neprojde celým stromem prostředku.
Při provádění přírůstkového sestavení nepracuje tvůrce s celým stromem prostředku, ale s jeho rozdílovými daty.
protected void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) throws CoreException { // návštěvník odvede práci. delta.accept(new MyBuildDeltaVisitor()); }
Proces návštěv pokračuje, dokud neprojde celým stromem rozdílových dat prostředku. Specifický charakter změn je podobný charakteru popsanému v tématu Implementace listeneru změn prostředků. Důležitým rozdílem je, že u přírůstkových tvůrců projektů pracujeme s rozdílovými daty prostředku založenými na konkrétním projektu, ne na celém pracovním prostoru.
Pracovní plocha umožňuje uživatelům vyčistit projekt nebo množinu projektů před zahájením sestavení. Tato vlastnost umožňuje uživateli vynutit úplné znovusestavení pouze nad určitými projekty. Tvůrci by měli tuto metodu implementovat, aby z projektu odstranili veškeré značkovače problémů a odvozené prostředky.
Chceme-li tvůrce zpřístupnit určitému projektu, musí být uveden ve specifikacích sestavení daného projektu. Specifikace sestavení projektu představují seznam příkazů, které se mají spustit v daném pořadí, když je projekt sestavován. Každý příkaz jmenuje jednoho přírůstkového tvůrce projektů.
POZNÁMKA: Název tvůrce v příkazu sestavení je úplné ID rozšíření tvůrce. Úplné ID rozšíření se vytváří kombinací ID modulu plug-in a ID jednoduchého rozšíření v souboru plugin.xml. Například tvůrce s ID jednoduchého rozšíření "mybuilder" v modulu plug-in "com.example.builders" se bude jmenovat "com.example.builders.mybuilder"
Následující úsek kódu přidává nového tvůrce jako prvního v již existujícím seznamu tvůrců.
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) { //přidat tvůrce do projektu ICommand command = desc.newCommand(); command.setBuilderName(BUILDER_ID); ICommand[] newCommands = new ICommand[commands.length + 1]; // Přidat ho před ostatní tvůrce System.arraycopy(commands, 0, newCommands, 1, commands.length); newCommands[0] = command; desc.setBuildSpec(newCommands); project.setDescription(desc, null); }
Konfigurace tvůrce projektu se provádí jen jednou, obvykle při vytváření projektu.