Il file common.build
, che si trova nella cartella Sample1
del file allegato, è ora decisamente più complesso ed inizia ad assomigliare ad un vero script di build. Per evitare di perdersi in un dedalo di target, di cui non è più ben chiara la dipendenza, è bene fin da subito iniziare ad impostare correttamente i nomi dei componenti base e dare loro una organizzazione logica. Per ottenere questo si può usare qualsiasi convenzione, l'importante e che sia possibile capire le operazioni svolte direttamente dal nome del target.
Il target build.common.init ad esempio ha lo scopo di inizializzare tutte le variabili comuni necessarie per la build, l'uso del carattere punto (.
) permette quindi di categorizzare in modo semplice i vari task. Entrando nel dettaglio di questo particolare target si può notare che in esso vengono solamente impostate delle proprietà, nella prima parte vengono create path.buildroot
e path.build
, rispettivamente utilizzate per memorizzare la directory radice degli artefatti e la cartella dove verranno realmente inseriti gli assembly risultato della compilazione.
<property name="path.buildroot" value="${path.root}/Artifacts/Builds" /> <property name="path.build" value="${path.buildroot}/${nant.settings.currentframework}" />
Il percorso base per la build è la sottocartella Artifacts/Builds
della cartella radice del progetto, mentre il reale percorso degli eseguibili è determinato dalla variabile nant.settings.currentframework che determina il framework utilizzato per la compilazione. Nel caso in esame gli assembly vengono quindi posizionati nella sottocartella net-3.5
che è il framework utilizzato di default da Nant. Di seguito inizia la gestione del numero di versione:
<property name="project.version.major" value="${version::get-major(version::parse(project.version))}" dynamic="true" /> <property name="project.version.minor" value="${version::get-minor(version::parse(project.version))}" dynamic="true" />
Questa parte presuppone che sia stata precedentemente impostata la proprietà project.version
, operazione solitamente effettuata dagli script dei singoli progetti.
L'aspetto interessante è che nant contiene al suo interno molte funzioni di utilità base come version::get-major()
e version::parse()
che consentono di scomporre un numero di versione nelle parti costituenti. In questo modo, nello script, si effettua un parsing della proprietà impostata per il progetto e si prelevano le sole proprietà major
e minor
. Per il build
e revision
invece si procede in maniera differente.
<if test="${not property::exists('CCNetLabel')}"> <property name="CCNetLabel" value="0"/> </if> <property name="project.version.build" value="${CCNetLabel}" overwrite="false" dynamic="true" /> <property name="project.version.revision" value="0" overwrite="false" />
Per il numero di build si incontra per la prima volta il task <if> che consente di eseguire dei sottotask in maniera condizionale. In questo caso si controlla con l'istruzione not property::exists('CCNetLabel')
se la proprietà CCNetLabel è già stata impostata, in caso contrario la si pone pari a zero.
I task condizionali sono assolutamente fondamentali per garantire la flessibilità dello script, in questo caso infatti si verifica se il numero di build sia già stato impostato dal CC.Net
(tool che verrà introdotto nel prossimo capitolo) ed in caso contrario lo pone pari a zero.
Le dichiarazioni delle proprietà build
e revision
sono poi marcate come overwrite="false"
, ad indicare che, se la proprietà è già stata creata, non deve essere sovrascritta.
Grazie a questa opzione è facile gestire il concetto di valori di default per le proprietà. Grazie all'attributo overwrite = "false"
si sta in pratica ottenendo lo stesso risultato dell'istruzione <if>
.
Quale delle due tecniche utilizzare è una questione di preferenze personali, per qualcuno evitare l'<if>
rende lo script più leggibile, per altri invece l'uso dell'overwrite rende è meno chiaro ed esplicito di una istruzione <if>
, per questa ragione nell'esempio sono state messe entrambe.
Sucessivamente si gestisce lo strongly typing.
<property name="project.keyfile" value="${path.root}/dotnetmarche.snk" dynamic="true" overwrite="false"/> <property name="project.option.signassembly" value="true" dynamic="true" overwrite="false" />
Si procede impostando la chiave da usare nella proprietà project.keyfile
, e anche in questo caso il valore overwrite="false"
indica un default, è infatti possibile per i singoli progetti utilizzare un file specifico. Immediatamente nel passo successivo si valorizza la proprietà project.option.signassembly
, per indicare che si desidera effettuare il sign del progetto.
L'ultima proprietà impostata è la project.path.propertiesdir
, che indica la directory in cui il progetto contiene il file assemblyinfo.cs
in cui sono definite le proprietà del progetto, nel caso di progetti C# di default questo file si trova nella sottocartella Properties
del progetto.
<property name="project.path.propertiesdir" value="${path.src}/Properties" dynamic="true" overwrite="false" />