NAnt

Bu aralar .NET uygulamalarımızı ekipçe geliştirirken kullanabileceğimiz entegrasyon araçları üzerine çalışıyoruz. Bu yüzden bu ve bundan sonraki birkaç gönderide .NET ile uygulama geliştiren kişi ve ekiplerin kullanabilecekleri araçların birkaçından bahsetmek istiyorum. Bunu, okuduğum birçok (İngilizce) kaynaktaki gibi düz bir biçimde yazarak yapmak istemedim. Onun yerine Robert C.Martin'in Craftsman makale serisinden ve Tom DeMarco'nun Deadline kitabından etkilenerek aklıma gelen diyaloglar biçiminde yazma yöntemini kullanmaya karar verdim. İlk gönderi ile başlayalım. Beğenilirse devam edelim.

İlk olarak kahramanlarımızın konusu oluşturma aracı NAnt olan konuşmalarına kulak verelim.

Emre: E abi son zamanlarda nelerle uğraşıyorsunuz?
Selçuk: Şu sıralar NAnt ile uğraşıyoruz. Duymuşsundur.

Emre: NAnt mı? Hayır, hiç duymadım. Yine sizin şu garip icatlarınızdan biri mi yoksa? Nedir?

Selçuk: Nant açık kaynak kodlu bir yazılım. Bir oluşturma aracı -build tool. Yani kodların derlenmesi ve kaynak dosyaların kütüphaneler (assembly) biçimine dönüştürülmesi işini yapıyor kısaca.

Emre: Oluşturma aracı mı? Böyle birşey neden kullanmak isteyeyim ki? Visual Studio kullanılyorum ve "Rebuild Solution" komutunu tıkladığımda bu dediklerini VS.NET benim için yapıyor.

Selçuk: Diyelim ki oluşturma işini otomatikleştirmek istiyorsun. Aslında istiyorsunuz demek daha doğru olur çünkü geliştirme işini bir ekip olarak yaptığınızı varsayıyorum. Ayrıca oluşturma süreci sadece kodların derlenmesi ve kaynak dosyaların kütüphaneler biçimine dönüştürülmesi demek olmayabilir. İşin içine, Source Control uygulamasından -VSS, ClearCase vb.- kaynak kodun son halini almak, birim testleri çalıştırmak, bu birim testlerin kodun ne kadarını kapsadığının kontrolünü yapmak, kaynak koddan dökümantasyon yaratmak ve oluşturmaya özgü konfigürasyon ayarlarının yapılması vb. adımlar da girebilir. Böyle bir durumda, oluşturma işini, oldukça esnek yapıda olan bu tip bir araçla yapmak isteyebilirsin. Biz de zaten NAnt ile bu yüzden ilgileniyoruz. Kullanmayı düşündüğümüz otomatik integrasyon aracı da CruiseControl.net ama istersen ondan daha sonra söz edelim, çünkü henüz o konuda NAnt kadar çalışmadık. Ha, bu arada NAnt Visual Studio'ya ihtiyaç duymuyor, yani herhangi başka bir kod editörünü kullanıyor olabilirdin.

Emre: Tam anlamıyla anlayamadım ama ilgimi çekmedi değil. Adı da bir garip, nereden geliyor?

Selçuk: Aslında NAnt da bir çok açık kaynak kodlu .NET projesi gibi Java dünyasındaki ağabeyini izliyor. Bunun birçok örneğini görebilirsin, örneğin CruiseControl-CruiseControl.Net ve JUnit-NUnit gibi. NAnt, Java geliştiricileri için açık kaynak kodlu frameworkler geliştiren Apache organizasyonunun oluştruma aracı olarak yarattığı Ant'ın .NET versiyonu. Anlamı için ise ant.apache.org sitesine başvurabilirsin.

Emre: İlginç. Biraz daha bahsetsene şu NAnt'tan.

Selçuk: Öncelikle NAnt kullanabilmek için şu CLR'lardan birine ihtiyacın var, ya da başka bir deyişle NAnt bu CLR'ları destekliyor demek daha doğru:

  • Microsoft .NET Framework 1.0

  • Microsoft .NET Framework 1.1

  • Microsoft .NET Framework 2.0 Beta 1

  • Mono 1.0.x


Ayrıca NAnt birkaç başka açık kaynak kodlu kütüphaneye de gereksinim duyuyor. Bunlar Nunit, NDoc ve SharpZipLib. Ama bunlar, NAnt'ı sitesinden indirdiğinde onunla birlikte geliyor endişelenme. Bu adresten ister yalnızca çalıştırılabilir dosyaları ister tüm kaynak kodu indirebilirsin. İndirdiğin zip dosyasını istediğin bir yere aç ve NAnt'ın \bin klasörünü PATH'ine ekle. Beni daha fazla dinlemek istemezsen hemen gidip bunları yapabilir ve en son adım olarak "nant -help" yazarak kendin araştırmaya başlayabilirsin. İndirdiğin zip dosyasının içinden NAnt sitesindeki help sayfalarının kopyalarını içeren bir \doc klasörü de çıkıyor ama ben derim ki gel sen beni dinlemeye devam et.

Emre: Tabi tabi can kulağıyla dinlemedeyim. Sen devam et.

Selçuk: Aslında NAnt temel olarak XML formatında hazırlanan .build uzantılı bir dosyayı okuyarak orada belirtilen işleri gerçekleştiriyor. O yüzden ben bu dosyanın hazırlanmasını anlatayım istersen. Çünkü gerisi kolay; sadece komut satırında "nant.exe" yazman yeterli. Nant öncelike o anki dizinde .build uzantılı dosya arıyor. Böyle birden fazla dosya varsa dosya adı vermelisin. Ya da bir üst dizindeki dosyayı kullanması için "nant -buildfile:..\dosyaAdi.build" yazabilirsin. Hatta NAnt'a build dosyasının içinde hangi target'ı çalıştıracağını bile "NAnt targetAdi" biçiminde söyleyebilirsin.

Emre: Target mı? Haydaa o ne şimdi?

Selçuk: Haklısın, gel target mevzuuna girelim. Ama önce söylemek istediğim birşey var. Build dosyalarının yapısını anlamak için güzel bir yöntem NAnt'ın kendi build dosyasına (nant.build) bakmak olabilir. Ama uyarayım ürkebilirsin, yeni başlayanlar için biraz karmaşık.
Evet ne sormuştun. Hımm target dedim ve açıklamadım değil mi? Şimdi... Her NAnt build dosyası bir projeden (project) ve bir veya daha fazla target'dan oluşur ve her target da yine bir veya daha fazla task içerir. Aslında küçük bir örnek yazsam saatlerce anlatmama bedel olacak. Bak şöyle küçük bir örnek yazabiliriz:

< ?xml version="1.0"?>
<project name="Meraba Televole" default="build" basedir=".">
<description>Meraba Televole oluşturma dosyası</description>
<property name="debug" value="true" overwrite="false" />
<target name="clean" description="tüm dosyaları silelim">
<delete file="MerabaTelevole.exe" failonerror="false" />
<delete file="MerabaTelevole.pdb" failonerror="false" />
</target>
<target name="build" description="oluşturalım" depends="clean">
<csc target="exe" output="MerabaTelevole.exe" debug="${debug}">
<sources>
<includes name="MerabaTelevole.cs" />
</sources>
</csc>
</target>
</project>

Al işte sana iki target "clean" ve "build". Aslında bu birçok şeyi açığa çıkarıyor değil mi? Ama gel ben anlatmaya devam edeyim. "basedir" özelliği, bu işte dizin adresi hesaplamaları için alınacak referansı belirtiyor. NAnt bu dosyayı ele aldığında, komut satırında belirtilmediyse hangi target'ı çalıştıracağını bilmeli, o yüzden varsayılan bir target "default" özelliğiyle tanımlanıyor. Bir de dosya boyunca kullanılmak istenen değişkenler tanımlanabiliyor. Bunlara "property" deniyor ve örnekteki gibi tanımlanıp "${özellikadı}" biçiminde dosya içinde kullanılıyor. NAnt'ın yerleşik özellikleri (property) de var ama onlara sen dökümanlardan bakarsın.
Gelelim build target'ındaki "depends" kavramına. Eğer bir target'ın çalıştırılması başka bir target'ın çalıştırılılmış olmasına bağlamak istersen bunu "depends" ile yapıyorsun. Buraya birden fazla target'ı virgülle ayırarak da yazabilirdik. Ayrıca target'a "if" ve "unless" kavramlarını ekleyerek koşullu çalışır duruma da getirbilirsin. "if" içinde verilen önerme true dönüyorsa target çalışır, "unless" içindeki true dönerse o target pas geçilir. Ama gel onun da ayrıntılarına girmeyelim ihtiyaç duyduğunda belgelerden bakabilirsin. Küçük bir örnek de vermeden de geçmeyeyim ama.

<target name="build-module-A" unless="${file::exists('module-a.dll')}" />

Gelelim task'lara. Task'lar çalıştırılabilecek kod parçalarıdır. Örnekte "delete" ve "csc" taskları var. Başka örnekler copy, exec, echo, mail, nunit ve zip olabilir. Gördüğün gibi aslında tüm işi bu task'lar yapıyor. Taskların target ve project'den farkı onları task etiketi ile değil kendi isimleri ile etiketliyor oluşumuz. Ayrıca her taskın kendine özgü içiçe geçmiş elemanları var. Örnek olarak copy taskini ele alalım. Bu taskı bir ya da daha çok dosyayı farklı bir yere kopyalamak için kullanabilirsin. Copy taskinin iki içiçe geçmiş bileşeni var. Fileset ve filterchain. Fileset kopyalanacak dosyaları seçmek için filterchain ise dosyayı kopyalandıktan sonra değiştirmek için kullanılıyor. Örneklemek için şunları yazabilirim:

<copy todir="../yedek/dir">
<fileset basedir="kaynak_dir">
<include name="**/*" />
</fileset>
<filterchain>
<replacetokens>
<token key="FILE" value="yedek" />
</replacetokens>
</filterchain>
</copy>

Bu task, "kaynak_dir" klasöründeki ve altındaki tüm klasörlerdeki dosyaları "yedek/dir" adresine kopyalar ve dosyalarda @FILE@ geçen yerlere "yedek" yazar. Tasklardan sözetmeye devam edersek bu sohbet çok uzayacak sen iyisi mi tüm taskların listesine belgelerdeki Task Reference'den bak ve işine yarayacağını düşündüklerinin detaylarını oku.
Gelelim diğer unsurlara. Loggerlar, Listenerler, Expressionlar ve Functionlar. Oluşturma işini izleyebilmek için logger ve listener kullanıyoruz. Adlarından da anlaşıldığı gibi listenerlar belli olaylar sırasında veya sonrasında uyarılırlar. Loggerlar ise standart çıktı ve hata sonuçlarını alıp konsola ya da "-logfile" ile kendilerine gösterilen dosyaya log yazarlar. Xml ve mail loggerlar sık kullanmak isteyebileceğin türden kavramlar. Maillogger'a mail atabilmesi için gerekenleri, xmllogger'a da dosya adı vermen yeterli. "Örnek" der gibi bakıyorsun, al bakalım o zaman:

NAnt.exe -logger:NAnt.Core.MailLogger
NAnt.exe -logger:NAnt.Core.XmlLogger -logfile:buildlog.xml

Task argümanlarında ve koşullu çalıştırmak istediğin taskların koşullarında kullanman için Nant exressionlar da sunuyor. Bunun için yerleşik expression kullanabilirsin. Sayısal, boolean, string ve tarih-zaman değerleri için oldukça çok sayıda yerleşik expression mevcut. Bunlar için de seni NAnt yardım dosyalarına yönlendirmek zorundayım zira programlama ya da script dillerinde rastlayabileceğin birçok ortak expression NAnt'ta da kullanılıyor ve çok fazla sayıda örnek yardım dosyalarında var. Expressionları ${...} biçiminde kullanabiliyorsun. Sen şimdi yine örnek istersin:

<property name="myprj.basedir" value="c:\" />
<property name="dosyaadi" value="${path::combine(myprj.basedir, 'surum.txt')}" />

<if test="${not file::exists(filename) or file::get-length(filename) = 0}">
<echo message="Sürüm dosyası: ${dosyaadi} yok ya da boş!" />
</if>

Expressionlar gibi functionlar da programlama ya da script dillerinde rastlayabileckerinle ortaklıklar sergiliyor. Nant işlevleri ile metinleri, tarih ve saat değerlerini, klasör adreslerini değiştirebilir, o anki oluşturma işleminin detay bilgilerine ulaşabilir ya da dosya ve klasörlerin detaylı özelliklerine erişebilirsin. Functionlar, başlangıç::function-adı(argüman1,..., argümanN) biçiminde kullanılıyor. Örnek olarak string::contains('NAnt','a') verilebilir. Bu arada unutmadan belirteyim, istersen kendi işlevlerini de yazabilirsin. Açıkçası bunu hiç kullanmadık. Unutma ben sadece senin merakını gidermeye, bu ve benzeri araçları kullanmanı sağlamaya çalışıyorum. Bunların ikisini de başarabilirsem senin işin asıl o nokada başlayacak ve yardım dosyaları ile google (adres) bu konuda benden sonraki rehberlerin olacak. Bu arada dinliyorsun değil mi? Yoksa çok mu hızlı gittim?

Emre: Aslında yakalamakta biraz güçlük çekiyorum. Benim aklıma daha basit şeyler takıldı. Mesela ben bu build dosyalarını VS.NET içinden yazmak istesem sürekli dönüp yardım dosyalarına bakmadan yapmak isterim. VS.NET'in intellisense'inde faydalanabilir miyim?

Selçuk: E tabi. Öncelikle .build uzantılı dosyanı yarat. Sonra Solution Explorer'dan sağ tıklayıp menüden Open with… komutunu tıkla. Açılan pencerede HTML/XML Editor'u seç ve önce Set As Default'ı sonra da Open'ı tıkla. Böylece bundan böyle VS.NET .build uzantılı dosyalarını HTML/XML Editor'u ile açacak. Şimdi NAnt'ın schema dosyasını (NAnt altında schema klasörü içinde nant.xsd) VS.NET kurulum adresi altında \Common7\Packages\schemas\ klasörü altına kopyala. Sonra .build uzantılı doyanın içeriğine tıklayıp Properties bölmesini açmak için F4'e bas. Burada targetSchema olarak az önce kopyaladığın schema dosyasını seç. Aslında yaptığımız sadece VS.NET'e gerekli schema'yı tanıtmak, artık intellisense build dosyası oluştururken sana yardımcı olacak.

Emre: İşte şimdi tamamdır. Ben ilk fırsatta örnek bir proje ile NAnt'ı kurcalamaya başlarım. Sana da teşekkür etmem gerek zira bir saattir anlatıyorsun.

Selçuk: Önemli değil. Sen yeter ki bu araçlarla tanış. Şimdi benim de biraz işim var. Ama sohbetimiz sırasında adı geçen bazı başka araçlar ve kavramlar oldu. Onlardan da sana bahsetmek isterim. Bir ara ikimizin de zamanı olduğunda yine buluşalım.

Emre: Şimdiden biraz ipucu versen. Nelerden söz edeceğiz?

Selçuk: Örneğin birim testler konusu geçti az önce. Sana ilk olarak bu konudan yani NUnit'ten bahsetmek istiyorum. Hatta o zaman Nunit'ı Nant ile birlikte kullanmaktan da bahsederiz. Tahmin edeceğin gibi bunun için NAnt'da bir task var. Ama bunlardan o zaman konuşalım olur mu? Şimdi gitmeliyim.

Emre: E hadi bakalım. Görüşürüz.


spinodal tarafından 19.04.2005 tarihinde yazılmıştır.

Labels: , ,

1 Comments:

Blogger timur g. said...

gerçekten anlatım olarak çok güzel bir yazı olmuş. nant a hızlı bir giriş yapmış oldum.

teşekkürler

http://www.isarayan.org

6/11/2008 12:43 AM  

Post a Comment

Subscribe to Post Comments [Atom]

<< Home