隨着IT行業的不斷髮展,軟件開發的複雜度也隨着不斷提升。與此同時,軟件的開發團隊也愈來愈龐大,而如何更好地協同整個團隊進行高效準確的工做,從而確保軟件開發的質量已經慢慢成爲了開發過程當中不可迴避的問題。php
在軟件開發中,不一樣的功能模塊通常由不一樣的開發成員負責,同一功能模塊的各層代碼也多是不一樣的開發成員編寫,經驗告訴咱們,模塊之間的問題是最難解決的,也是最耗費時間的。它須要多個開發人員相互協做找出問題,而協做過程當中的溝通所消耗的時間成本是至關高的。並且還可能由於溝通的不足致使模塊返工。html
事實上,在持續集成被提出來以前的傳統開發方法中經常出現這種狀況:由不一樣程序員開發的單個小模塊能夠單獨工做,但把它們集成爲一個大的系統則可能失敗。並且集成失敗每每是把集成放在開發週期後期,甚至是在項目快結束前單列的一個「總裝階段」。衆所周知,問題發現的越晚,其修復的成本也就越高,耗時越長,並且通過新的修復工做後可能誕生新的錯誤,所以整個系統須要再次進行集成和測試,從而致使整個軟件的生產週期漫長且不可預知。java
上述傳統開發方法帶來的高集成成本和長開發週期將直接帶來了顯著的影響:首先是沒法爲客戶提供穩定的產品,其次下降了開發團隊的士氣。開發團隊士氣下降將進一步致使產品開發的不順,進而造成開發的惡性循環。python
爲了解決由傳統開發方法帶來的弊端,人們開始採用「早集成、常集成」的持續集成策略。從最初的分階段集成,到後來的「每日構建」[1] , 再發展到如今的持續集成(Continuous Integration,CI)[2]。持續集成經過自動化構建、自動化測試以及自動化部署加上較高的集成頻率保證了開發系統中的問題能迅速被發現和修復,下降了集成失敗的風險,使得系統在開發中始終保持在一個穩定健康的集成狀態。mysql
研究基於Jenkins的軟件自動構建系統的目的與意義在於:android
首先,持續集成服務器是自動構建系統中關鍵的一部分。Jenkins是一個開源項目,它提供了一種易於使用的持續集成系統,使開發者從繁雜的集成中解脫出來,專一於更爲重要的業務邏輯實現上。同時 Jenkins 能實施監控集成中存在的錯誤,提供詳細的日誌文件和提醒功能,還能用圖表的形式形象地展現項目構建的趨勢和穩定性。[3]Jenkins還能經過自定義安裝插件來實現多種多樣的功能,目前Jenkins擁有超過600種的插件,基本能夠知足你的大多數需求。Jenkins能夠算是最近比較熱門的持續集成服務器,許多公司和開源項目都在使用Jenkins,好比Facebook、GitHub、Yahoo!、Apache、Ubuntu等。git
其次,中小型軟件企業數量衆多,其開發團隊和項目也大可能是中小型的,所以有大量能夠採用輕量開發方法的空間。持續集成是輕量開發方法中一個很是重要的實踐,是保證團隊開發步調一致和保證開發質量的重要手段。將持續集成指導下的自動構建系統融合到開發過程當中將大幅度提升軟件質量,下降開發成本[4]。程序員
再者,可將自動構建系統引入高校計算機類專業的教育環節中。一方面老師能夠經過實際的軟件項目來引導學生體驗軟件開發的實際流程,提升學生的興趣和實踐能力。另外一方面也能讓外界對校內進行的開發項目有直觀的認識,提高學校知名度。web
本課題研究主體肯定爲基於Jenkins的軟件自動構建系統。主要對持續集成這一實踐進行調查和分析,研究如何實現軟件的自動化編譯,自動化測試,自動化部署以及文檔自動化生成及發佈。在此基礎上結合Jenkins持續集成服務器和Gerrit代碼源碼管理系統實現一個穩定的軟件自動構建系統。正則表達式
2001年,爲了解決許多公司的軟件團隊陷入不斷增加的過程泥潭,一批業界專家一塊兒歸納出了一些可讓軟件開發團隊具備快速工做、響應變化能力的價值觀和原則,他們稱本身爲敏捷聯盟。敏捷開發過程的方法不少,主要有:SCRUM,Crystal,特徵驅動軟件開發(Feature Driven Development,簡稱FDD),自適應軟件開發(Adaptive Software Development,簡稱ASD),以及最重要的極限編程(eXtreme Programming,簡稱XP)。極限編程(XP)是於1998年由Smalltalk社羣中的大師級人物Kent Beck首先倡導的。
極限編程(XP)是敏捷方法中最著名的一個。它是由一系列簡單卻互相依賴的實踐組成。這些實踐結合在一塊兒造成了一個勝於部分結合的總體。
下面是極限編程的有效實踐:
(1)完整團隊 XP項目的全部參與者(開發人員、客戶、測試人員等)一塊兒工做在一個開放的場所中,他們是同一個團隊的成員。這個場所的牆壁上隨意懸掛着大幅的、顯著的圖表以及其餘一些顯示他們進度的東西。
(2)計劃遊戲計劃是持續的、按部就班的。每2周,開發人員就爲下2周估算候選特性的成本,而客戶則根據成本和商務價值來選擇要實現的特性。
(3)客戶測試做爲選擇每一個所指望的特性的一部分,客戶能夠根據腳本語言來定義出自動驗收測試來代表該特性能夠工做。
(4)簡單設計團隊保持設計剛好和當前的系統功能相匹配。它經過了全部的測試,不包含任何重複,表達出了編寫者想表達的全部東西,而且包含儘量少的代碼。
(5)結對編程全部的產品軟件都是由兩個程序員、並排坐在一塊兒在同一臺機器上構建的。
(6)測試驅動開發編寫單元測試是一個驗證行爲,更是一個設計行爲。一樣,它更是一種編寫文檔的行爲。編寫單元測試避免了至關數量的反饋循環,尤爲是功功能能驗證方面的反饋循環。程序員以很是短的循環週期工做,他們先增長一個失敗的測試,而後使之經過。
(7)改進設計隨時利用重構方法改進已經腐化的代碼,保持代碼儘量的乾淨、具備表達力。
(8)持續集成團隊老是使系統完整地被集成。一我的拆入(Check in)後,其它全部人責任代碼集成。
(9)集體代碼全部權任何結對的程序員均可以在任什麼時候候改進任何代碼。沒有程序員對任何一個特定的模塊或技術單獨負責,每一個人均可以參與任何其它方面的開發。
(10)編碼標準,系統中全部的代碼看起來就好像是被單獨一人編寫的。
(11)隱喻,將整個系統聯繫在一塊兒的全局視圖;它是系統的將來影像,是它使得全部單獨模塊的位置和外觀變得明顯直觀。若是模塊的外觀與整個隱喻不符,那麼你就知道該模塊是錯誤的。
(12)可持續的速度,團隊只有持久纔有獲勝的但願。他們以可以長期維持的速度努力工做,他們保存精力,他們把項目看做是馬拉松長跑,而不是全速短跑。 極限編程是一組簡單、具體的實踐,這些實踐結合在造成了一個敏捷開發過程。極限編程是一種優良的、通用的軟件開發方法,項目團隊能夠拿來直接採用,也能夠增長一些實踐,或者對其中的一些實踐進行修改後再採用。
極限編程中有四個核心價值是咱們在開發中必須注意的:溝通(Communication)、簡單(Simplicity)、反饋(Feedback)、勇氣(Courage)、此外還擴展了第五個價值觀:謙遜(Modesty)。 XP用「溝通、簡單、反饋、勇氣和謙遜」來減輕開發壓力和包袱;不管是術語命名、專著敘述內容和方式、過程要求,均可以從中感覺到輕鬆愉快和主動奮發的態度和睦氛。這是一種幫助理解和更容易激發人的潛力的手段。XP用本身的實踐,在必定範圍內成功地打破了軟件工程「必須重量」才能成功的傳統觀念。
軟件集成是一個軟件開發過程,在這個過程當中,經過管理和技術手段,將已開發出的軟件組件或代碼單元,整合成完整的軟件產品,並對該產品進行測試和驗證以確保產品符合用戶需求,一般也被稱做系統集成或集成測試。所以集成方式對於軟件開發的重要性不言而喻。下面對幾種經典的軟件開發模型的集成方式進行比較:
瀑布模型[5]是最先出現的軟件開發模型,其過程是從上一項活動接收該項活動的工做對象做爲輸入,利用這一輸入實施該項活動應完成的內容給出該項活動的工做成果,並做爲輸出傳給下一項活動。同時評審該項活動的實施,若確認,則繼續下一項活動;不然返回前面,甚至更前面的活動。以下圖所示。
圖2. 1 瀑布模型
從上可知瀑布模型本質是一種線性順序模型。在開始下一階段工做前必須完成上一階段的全部工做。然後一階段出現了問題要從前一階段從新確認解決。因此當問題發現的越晚,解決問題所須要付出的代價就越高。
相對應的,瀑布模型的集成方式可總結爲兩個步驟:首先是每一個模塊的需求分析、設計、編碼、測試和調試,至關於單元模塊開發;而後是將各單元模塊進行系統集成。
各個模塊在系統集成前並無一塊兒工做過,所以首次系統集成必然出現許多新問題,一旦出現問題,則全部模塊都須要進行調試。通常把這種集成方式成爲Big-Bang集成。這種集成方式前提是模塊之間的獨立性較高,而現代軟件開發中開發人員之間的相互合做依賴程度愈來愈高,幾乎不可能存在相互獨立的模塊。並且不少bug都是在後期的集成中才發現的,這樣將直接致使高昂的系統修復代價,嚴重影響了開發進度,同時使得項目開發進度和現狀難以預估。所以Big-Bang集成方式只適用於模塊間相互獨立的小型項目。
隨後Rational公司提出了Rational統一過程(簡稱RUP)。RUP方法中,經過迭代將整個項目的開發目標劃分紅爲一些更易於完成和達到的階段性小目標,這些小目標都有一個定義明確的階段性評估標準。迭代就是爲了完成必定的階段性目標而所從事的一些列開發活動。在每一個迭代開始前都要根據項目當前的狀態和所要達到的階段性目標制定迭代計劃,整個迭代過程包含了分析、設計、編碼和測試等開發活動,迭代完成後須要對完成的結果進行評估,並以此爲依據來制定下一次迭代的目標,以下圖所示。
圖2. 2 RUP遞增迭代模型
迭代RUP的集成模式步驟分爲三步[6]:
(1)開發系統中一個小的功能模塊,它能夠說最小的功能塊,但應該是系統中一個關鍵部分,完全檢查調試,而後將該模塊做爲一個核心,在它基礎上設計系統的其餘部分模塊;
(2)設計、編碼、檢查和調試程序;
(3)將這些新程序代碼集成到已經完全測試的核心模塊上。檢查、調試核心模塊和這些新程序的組合,在加入新程序以前,必定要確保組合工做正確,若是其他工做已被完成,重複過程從第二部開始。
整個集成過程是一個遞增的過程,一般把這種集成方法稱爲「遞增迭代」集成。
遞增迭代集成能容易的肯定錯誤位置——錯誤必定在新程序功能模塊上。並且因爲每次只集成少許代碼程序,所以出現的問題數量也大大減小,下降因爲多個問題相互做用產生新問題或者問題間相互掩蓋的風險。大大提升的開發效率。
因爲迭代遞增過程當中沒有量化迭代間隔和每次增長人物的工做量,從而在實踐中容易出現「迭而不增」和「增而不迭」兩種錯誤。「迭而不增」變成簡單的重複,並無增長實際的功能;「增而不迭」變回了簡單的線性模型
微軟過程模型(MSF)[7]和「每日構建」集成模式是上述問題的解決方法之一。微軟過程模型是由微軟公司根據自身實踐經驗爲企業設計的一套有關軟件開發的準則。MSF過程模型是一種基於階段的,由里程碑驅動的,遞進的軟件開發模型。
MSF過程模型建議項目組首先建立、測試和提供包含核心功能的產品模塊,而後再向其中添加功能,提出後續版本。通常被稱爲遞進的版本發佈策略。每一個版本表明一個開發階段,這種作法更有利於產品的質量,也更便於在開發過程當中對項目進行調整。MSF要求項目組在開發過程當中迅速完成每一次遞增過程,並在每一次開發週期中都能切實的增長產品的特性,提升產品質量。
MSF其對應的集成模式爲「每日構建」(Daily Build)。每日構建包括如下步驟:
(1)按期檢查源代碼庫;
(2)若是源代碼庫中發生改變將觸發構建和後續測試;
(3)給源代碼庫的當前構建做一個標籤,以便未來能夠在當前夠的基礎上進行從新構建;
(4)給相應開發人員發送構建狀況反饋。
MSF把集成變成了簡單的工做,並把迭代間隔量化爲天天,迭代的增量爲天天的工做量,解決了迭代遞增集成中容易出現的問題。
技術的發展開始呈現出高速化的姿態,在此驅動下,軟件開發也必須實現快速化的開發以適應技術的發展。此時敏捷開發便出現了,簡單的說,敏捷開發是一種以人爲核心、迭代、按部就班的開發方法。它以適應性的過程來代替傳統的預測性的過程,在很大程度上知足了現代商業軟件業務複雜、需求多變、時間要求緊迫等特色。
相比瀑布式開發漫長嚴格的開發週期,敏捷開發要求在幾周或者幾個月的時間內完成相對較小的功能,強調的是能將盡早將盡可能小的可用的功能交付使用,並在整個項目週期中持續改善和加強。而相比一樣強調較短開發週期的迭代式開發,敏捷開發的週期更短,並更注重隊伍中的高度協做。
而極限編程做爲敏捷開發的方法之一,其中有一項最佳實踐,即持續集成。極限編程認爲:項目天天能夠構建屢次,而不僅一次,每日構建是最低要求。一個徹底自動化的過程應該讓項目天天完成屢次構建,這是可行的。在工做幾個小時的開發後,就要對剛纔工做的代碼進行集成和測試,並快速得到反饋。持續集成雖然是出自極限編程的實踐,但隨着持續集成的發展,它已經開始做爲一種優秀的軟件開發實踐應用於各類開發方法中。
持續集成[8]與「每日構建」相比有幾點不一樣:首先,持續集成比每日構建的集成頻率更高,具體依據項目而定;再者持續集成在集成失敗後向開發人員提供快速的反饋,讓開發人員能夠迅速修復錯誤,而不只僅是在成功構建後提供一個穩定的版本;最後持續集成鼓勵開發人員頻繁的提交代碼修改並獲得儘快的反饋,每次修改的代碼量減小後,出現問題的修復也變得容易和迅速。
業界廣泛認同的持續集成的原則[9]包括:
(1)須要版本控制軟件保障團隊成員提交的代碼不會致使集成失敗。經常使用的版本控制軟件有 ClearCase、CVS、Subversion、Git 等;
(2)開發人員必須及時向版本控制庫中提交代碼,也必須常常性地從版本控制庫中更新代碼到本地;
(3)須要有專門的集成服務器來執行集成構建。根據項目的具體實際,集成構建能夠被軟件的修改來直接觸發,也能夠定時啓動,如每半個小時構建一次;
(4)必須保證構建的成功。若是構建失敗,修復構建過程當中的錯誤是優先級最高的工做。一旦修復,須要手動啓動一次構建。
(1)一天中進行屢次的集成,並作了相應的測試,這樣有利於檢查缺陷,瞭解軟件的健康情況。
(2)減小重複的過程能夠節省時間、費用和工做量。提及來簡單,作起來難。這些浪費時間的重複勞動可能在咱們的項目活動的任何一個環節發生,包括代碼編譯、數據庫集成、測試、審查、部署及反饋。經過自動化的持續集成能夠將這些重複的動做都變成自動化的,無需太多人工干預,讓人們的時間更多的投入到動腦筋的、更高價值的事情上。
(3)持續集成能夠在任什麼時候間發佈能夠部署的軟件。從外界來看,這是持續集成最明顯的好處,咱們能夠對改進軟件品質和減小風險提及來口若懸河,但對於客戶來講,能夠部署的軟件產品是最實際的資產。利用持續集成,您能夠常常對源代碼進行一些小改動,並將這些改動和其餘的代碼進行集成。若是出現問題,項目成員立刻就會被通知到,問題會第一時間被修復。不採用持續集成的狀況下,這些問題有可能到交付前的集成測試的時候才發現,有可能會致使延遲發佈產品,而在急於修復這些缺陷的時候又有可能引入新的缺陷,最終可能致使項目失敗。
(4)持續集成讓咱們可以注意到趨勢並進行有效的決策。若是沒有真實或最新的數據提供支持,項目就會遇到麻煩,每一個人都會提出他最好的猜想。一般,項目成員經過手工收集這些信息,增長了負擔,也很耗時。持續集成系統爲項目構建狀態和品質指標提供了及時的信息,有些持續集成系統能夠報告功能完成度和缺陷率。再者因爲常常集成,咱們能夠看到一些趨勢,如構建成功或失敗、整體品質以及其它的項目信息。
(5)持續集成能夠創建開發團隊對開發產品的信心,由於他們清楚的知道每一次構建的結果,他們知道他們對軟件的改動形成了哪些影響,結果怎麼樣。而長期穩定的成功構建將極大的鼓舞團隊的士氣。
(1)團隊開發。工程化軟件開發中的開發團隊規模每每上百人,且工程中又有許多分支,這時就須要統一的工程管理措施來確保準確有效的開發工做。
(2)做爲許多流行的軟件開發理論的基礎組成部分,例如敏捷開發,Staging Delivery,RUP 中的迭代開發等。拿敏捷開發來講,敏捷開發是一種以人爲核心、迭代、按部就班的開發方法。在敏捷開發中,軟件項目的構建被切分紅多個子項目,各個子項目的成果都通過測試,具有集成和可運行的特徵。換言之,就是把一個大項目分爲多個相互聯繫,但也可獨立運行的小項目,並分別完成,在此過程當中軟件一直處於可以使用狀態。
(3)運營與開發。像淘寶之類網站在進行開發、測試(壓力測試、兼容性測試等)、上線(同時要裝到N臺服務器上)、數據維護等均須要運用到持續集成技術。
持續集成概念發展的十多年間,早已經出現了許多用以支持這一律唸的工具,這些工具的組合使用爲軟件開發提供了強大的支持。
通常來講,持續集成工具能夠分爲兩大類:自動化構建工具和構建計劃安排工具。
(1)自動化構建工具
自動化構建工具備這樣一些基本功能:代碼編譯、組件打包、程序執行和文件操做。編譯源代碼是構建的主要工做之一,爲了提升效率,編譯應該根據相應的源代碼是否發生改變而有條件地執行。組件打包是將編譯的結果和其餘須要包含的文件組織在一塊兒,造成能夠部署的組件。構建工具應該知道什麼時候須要從新打包。程序執行是指構建工具可以在它支持的平臺上,調用全部提供命令行接口的程序。構建工具應該支持建立、拷貝、刪除文件和目錄等操做。
某些自動化構建工具還有一些擴展功能:執行開發者測試、版本控制工具集成、文檔集成、部署功能、代碼品質分析、支持擴展、多平臺構建、加速構建。雖然構建工具能夠經過命令行執行的方式來集成構建工具和測試工具,但若是它提供更直接的集成方式,開發者就更省力。一樣,若是構建工具可以直接與版本控制工具集成,開發者也會以爲更方便。文檔集成是指構建工具可以自動從源代碼中抽取並生成API文檔。構建工具還能夠將打包好的組件自動部署到目標測試環境中去。構建工具通常經過一些第三方插件,支持對代碼品質進行分析。而提供插件接口,是構建工具實現可擴展性的通用方式。若是您開發的軟件須要在多個平臺上構建並測試,那麼構建工具對多平臺的支持就會帶來極大的方便。對於較大的代碼集,一次構建可能須要好幾個小時,這爲持續集成帶來了一些挑戰。有的構建工具支持加速構建,即在多個構建服務器的多個處理器上進行分佈式構建。
常見的自動化構建工具包括Ant、NAnt、MSBuild、make、Maven、Rake、Doxygen等。
(2)構建計劃安排工具
構建計劃安排工具,一般也叫作持續集成服務器,其基本功能爲:構建執行、版本控制集成、構建工具集成、提供反饋、爲構建打上標籤。構建計劃安排工具的核心功能就是在特定時間執行自動化的構建,這能夠經過輪詢版本控制庫、計劃驅動或事件通知等方式來實現。大部分構建計劃安排工具都支持大多數流行的版本控制系統,也支持大多數流行的構建工具。構建計劃安排工具至少支持經過電子郵件提供反饋信息,有一些工具能夠經過即時消息、手機短信或其餘設備來提供反饋。大多數構建計劃安排工具會提供某種類型的升序計數,做爲構建版本的標籤。
某些構建計劃安排工具還有一些擴展功能:支持項目間依賴關係、提供用戶界面、製品發佈、安全。若是項目間存在依賴關係,您可能但願在被依賴的項目從新構建時,從新構建依賴於它的項目。設計良好的用戶界面會在工做時爲您節約時間。製品發佈是指除了獲得可部署的組件以外,一些成熟的某些構建計劃安排工具能夠將文檔、測試結果、品質分析結構和其餘測量指標數據格式化,便於查看。有一些工具提供了身份認證和受權等安全方面的功能,容許您指定誰能查看結果和修改配置。
常見的構建計劃安排工具包括AnthillPro、Continuum、CruiseControl、CruiseControl.NET、Draco.NET、Luntbuild、Jenkins等。
(3)其餘與持續集成相關的工具
現代軟件開發中必然有一個源碼管理系統來管理項目代碼,否則代碼的存儲將會雜亂無章。而一個完整的持續集成系統中必然也少不了這一工具。源碼管理系統也可稱爲版本管理工具,主要分爲兩種:集中式和分佈式。集中式版本管理表明爲Subversion(SVN),分佈式的表明爲:Git。Git還能夠配合代碼審覈工具Gerrit實現強制代碼審覈功能。Gerrit經過網頁的形式方便負責人對開發者提交的代碼進行審覈、評論等,省去了審覈人須要自行下載代碼在本地查看提交變化的流程。進一步方便了版本管理。Gerrit可結合持續集成服務器,爲每次代碼變動觸發一次自動編譯,若自動編譯沒法經過,則直接review不經過,省去審覈人時間。
一個完整的持續集成系統由如下幾部分組成:
(1)一個自動構建過程,包括自動編譯、分發、部署和測試等。可以使用ANT或者Maven等工具;
(2)一個代碼存儲庫,即須要版本控制軟件來保障代碼的可維護性,同時做爲構建過程的素材庫。例如Subversion、Git、CVS;
(3)一個持續集成服務器。Cruise Control、Jenkins等。
按照該組成,你能夠選用本身喜歡的工具來設計你本身的持續集成系統方案。好比PMS平臺(JIRA+CruiseControl+Subversion)[10]、Git+Jenkins+Gerrit[11]等。
自動構建系統由持續集成服務器、版本控制工具、構建工具構成。版本控制工具保證項目源碼處於有序的管理中,方便開發人員隨時獲取和提交變動。構建工具實現項目的自動構建、自動測試、自動部署等功能。持續集成服務器將三者結合起來共同完成從監測到版本改變、到自動編譯改變的代碼再到自動運行全部的單元測試用例,並輸出結果,完成自動化測試和監測代碼正確性的功能。持續集成發展至今,相關的工具也多種多樣。並且採用不一樣的工具來搭建自動構建系統,將帶來不盡相同的效果,但目的都是同樣的——最大程度的簡化軟件開發的過程。下面說明一下本設計採用的方案。
(1)持續集成服務器
持續集成服務器有十來種,可是經常使用的是CruiseControl和Jenkins。本設計中選用Jenkins,具體緣由以下:
Jenkins容易安裝和配置,並且提供了直觀靈活的基於web的用戶界面配置管理方案;
Jenkins具備強大的插件框架,目前已經擁有超過600中插件可供使用;
Jenkins支持多種構建語言,包括Python等;
Jenkins集成了RSS/Email通知機制;
Jenkins支持分佈式構建。
Jenkins的特色還有許多,相較之下CruiseControl則較爲厚重,並且配置須要經過config.xml來完成,界面比Jenkins要遜色許多,且擴展性沒有Jenkins來的強大(不得不說Jenkins做爲一個開源項目,其插件的開發作得很是出色)。所以,雖然Jenkins做爲一個後起之秀能漸漸取代當初流行的CruiseControl自有其道理在。
(2)版本控制管理工具
當下熱門的版本控制管理工具基本分爲兩種:分佈式和集中式的。其中分佈式表明爲Git,集中式的表明爲Subversion(SVN)。下面咱們來對比一下二者特色。
SVN可謂是集中式版本控制集大成者。集中式版本控制中,每一個人均可以必定程度上看到項目中其餘人正在作些什麼。而管理員也能夠輕鬆掌握開發者的權限,可是若是中央服務器宕機了,那麼全部的開發者都沒法進行提交更新、還原、對比也沒法協同工做,這樣對項目開發帶來了極大的風險。最可怕的是出現數據丟失的狀況。
Git的分佈式版本控制相比於集中式版本控制最大的不一樣是不須要集中式的版本庫,每一個人都工做在經過克隆創建的本地版本庫中。也就是每一個人都擁有一個完整的版本庫,開發者能夠在本地庫上作任何操做。加上多樣的協同工做模型(版本庫間的推送,拉回,補丁等)讓分佈式版本控制極大的促進了多人蔘加的協同工做。因爲不用聯網,使得工做處理速度極快。儘管Git沒法像SVN同樣對項目進行精細的受權,可是經過加入代碼審覈工具Gerrit也能實現詳細的受權管理。
綜上所述,本設計採用Git做爲版本控制工具。
(3)構建工具
在構建工具的選擇依基本是選擇Ant或者使用更爲強大的Maven,或者使用本身編寫的構建腳本。下面就Ant來闡述一下其優勢:首先,由於Ant使用JAVA實現,因此是跨平臺的;其次,與make相比,Ant語法清晰,使用簡單;再者,Ant配合插件使用可以實現許多功能。
(4)代碼檢測
對於JAVA項目能夠使用FindBugs進行靜態代碼檢測。FindBugs是檢查JAVA字節碼,即*.class文件,能夠幫助開發人員提升代碼質量以及排除隱含的缺陷。
(5)測試
對於測試工具的使用,依據項目而定。若是是C/C++項目則使用CppUnit,如果JAVA項目則使用JUnit。二者都是XUnit的成員,固然除了CppUnit和JUnit以外,XUnit還有PythonUnit等,均是基於測試驅動開發的測試框架,能讓咱們得以快速的進行單元測試。在進行單元測試後,還能夠經過Emma工具來進行單元測試的代碼覆蓋率的統計,方便以後對單元測試的完善。
本設計選用一臺機器做爲持續集成服務器主機,經過持續集成服務器Jenkins來進行設置。選用另外一臺機器做爲持續集成服務器的子機,用來分擔主機的任務壓力。並選用一臺機器專門做爲代碼倉庫,由代碼審覈工具Gerrit進行管理。持續集成服務器監視代碼倉庫,一旦代碼倉庫中有代碼修改提交,則自動從代碼倉庫拉下代碼,執行自動構建、代碼檢測、測試並把結果經過web和E-mail的形式及時反饋給開發人員。
一旦自動構建系統能穩定的運行,將給開發團隊帶來比較穩定且快速的開發效率,使得本來艱難的集成工做變成一件能在十來分鐘內(只考慮編譯測試)自動完成的輕鬆事,有效下降了因爲bug過晚發現致使修改代價太高的風險,進而提升軟件質量,鼓舞團隊士氣。
下面咱們基於以上的模型來描述一下該自動構建系統的工做過程。
首先,開發人員使用Git從代碼倉庫中拉下項目源碼,並在本地進行工做。在幾個小時工做後,準備向代碼庫提交修改代碼。提交過程分爲兩步:首先,開發人員在本地調試成功打算提交時,須要將最新的代碼庫同步到本機中,並檢查與最新的更改是否發生衝突,若是發生衝突則須要進行修改或者與其餘修改者進行協商解決衝突。而後在本地可以成功構建後再提交修改代碼。因爲咱們設置了代碼審覈服務器來管理Git倉庫,所以提交的代碼先進入代碼審覈環節,在沒有持續集成服務器的狀況下,代碼審覈須要審覈人手動進行修改代碼的review(拉下代碼、構建、審覈等),review後若代碼知足要求就能夠進行submit,代碼才正式merge進代碼倉庫中。在引入持續集成服務器後咱們能夠設置Gerrit的觸發事件,在每次有新的代碼提交時,自動觸發構建任務,並將結果反饋給Gerrit代碼審覈服務器,Gerrit將根據反饋結果決定對本次代碼修改採起的動做,成功則將本次變動merge到代碼庫中,不然打回本次修改,開發人員也會受到構建結果的通知。下圖簡要描述了該持續集成過程。
圖3. 2 持續集成流程
在前面兩節中咱們詳細描述了本設計中持續集成系統方案的核心工具的選用和其工做流程,但事實上,每一個使用持續集成技術的公司,他們的持續集成系統都有他們本身的特點和要求。這時候Jenkins強大豐富的插件框架就能體現出它得天獨厚的擴展能力:超過600種插件和可自主開發的開源環境讓你深深體會到:只有想不到,沒有作不到。下面咱們來介紹一下本設計方案中採用了哪些Jenkins的插件和第三方軟件的支持。
(1)自動文檔生成之Doxygen
Doxygen是一種開源跨平臺的,以相似JavaDoc風格描述的文檔系統,徹底支持C、C++、Java、Objective-C和IDL語言,部分支持PHP、C#。註釋的語法與Qt-Doc、KDoc和JavaDoc兼容。Doxgen能夠從一套歸檔源文件開始,生成HTML格式的在線類瀏覽器,或離線的LATEX、RTF參考手冊。
文檔的重要性對於程序員來講是不言而喻的,一個好的文檔可讓你的軟件更容易讓人理解和使用。可是編寫文檔歷來都是一件麻煩的事情。Doxygen做爲一款優秀的文檔自動生成工具,能夠將程序中的特定批註轉換成說明文件,而且能夠自動生成相關的類圖等,可是須要程序員在程序的註釋中多下點功夫。
而經過將文檔自動生成放入到咱們的自動構建系統中便可以輕鬆的實現定時或者觸發性的文檔自動生成和發佈。
再使用Jenkins的HTML Publisher plugin能夠輕鬆的把生成的文檔顯示在項目中。
(2)Gerrit Trigger、Git plugin、Git Client plugin
爲了使Jenkins可以獲取代碼審覈工具Gerrit的變動信息,須要安裝Gerrit Trigger plugin,安裝後經過簡要配置鏈接的用戶信息就可以實時的獲取Gerrit中的代碼狀況,並能監視變更進而觸發相應的自動構建事件,最終將構建結果反饋給Gerrit,並設置review和verify的值。
因爲咱們使用的版本控制工具爲Git,爲此咱們須要使用相應的Git插件來添加相應的Git代碼庫操做功能。
(3)SSH Slave plugin和Credentials plugin
有時候咱們有許多項目同時須要進行持續集成的時候,咱們就必須考慮引入額外的子機來分擔持續集成主服務器的工做壓力。這時候須要用到Jenkins的Master/Slave的服務器架構。Master和Slave機器之間的鏈接方式有許多種:SSH、Java web start、WMI+DCOM、本身的鏈接腳本。這裏偏向於使用SSH的鏈接方式,較爲方便。可是當對鏈接後須要作點額外的環境配置等工做的時候,就須要編寫本身的鏈接腳本了。再使用Jenkins的SSH Slave plugin就能添加經過SSH鏈接的子機節點了。
(4)FindBugs plugin和 Jenkins Emma plugin
使用FindBugs和Emma分別實現對Java代碼的靜態檢測盒單元測試的代碼覆蓋率統計,再經過對應插件將二者產生的結果經過圖形化的方式直觀的發佈在持續集成系統中,方便開發人員的查看。
(5)Jenkins TextFinder plugin
有時候咱們須要經過自動構建產生的構建信息或者指定文件的內容來決定本次構建是否成功,這時候就須要用到該插件。所要查找的字符串經過正則表達式來定義。還能指定須要查找的文件或者Jenkins控制檯輸出內容。
(6)Jenkins Mailer plugin
該插件實現構建結果的通知功能。當構建結果不穩定或者失敗的時候,能夠給指定的接收人郵箱發送郵件。接收人的郵箱地址支持變量輸入,好比$GERRIT_CHANGE_OWNER_EMAIL,能夠實現對向Gerrit提交代碼修改的人發送郵件。
(7)ThinBackup 和 Backup plugin
備份是維護一個系統很是重要的一環,Jenkins擁有強大的備份插件,能夠實現定時定量的內容備份。這裏有兩種插件可供使用:第一種爲ThinBackup,該插件能將Jenkins中的任務配置文件進行高效的備份,並支持定時備份;第二種爲Backup plugin,該插件直接將Jenkins的整個workspace文件夾進行拷貝,所以須要的時間也比較長,可是信息完整。通常狀況使用第一種進行短週期的備份便可(支持自動清理過舊的備份),在項目穩定後再使用第二種進行完整的備份。
(8)Role-based Authorization Strategy
該插件提供了一種基於角色的安全認證系統。管理員能夠經過該插件來建立對Jenkins擁有不一樣權限的角色,並對Jenkins用戶進行角色分配。從而提升Jenkins的安全性,防止外來人員惡意修改系統。
(9)Android Emulator plugin
該插件極大便利了Android項目的開發,它支持自動啓動Android Emulator從而實現對Android項目的仿真測試。經過插件參數配置能夠實現自定義的Emulator,經過建立multi-configuration project還能實現對不一樣參數Emulator的仿真測試對比。
(10)Dashboard View 和Extra Columns plugin
當處於持續集成下的項目多了以後就須要對Jenkins的Web顯示界面進行管理,將項目按照必定的規則進行組的劃分並歸到相應的視圖下,方便查看,使用Dashboard View便可完成此功能。若須要在每一個項目欄上添加快捷的按鈕,如最近的構建信息等,使用Extra Columns plugin能夠實現自定義的添加修改。
Jenkins的插件十分豐富,如何有效的使用這些插件來進一步簡化持續集成工做是很是重要而有意義的,要認識到有時候發現或者設計一個便利的插件可能會大大提升集成的效率和質量。
Elastos操做系統是目前科泰公司正在開發的系統,本設計的自動構建系統將着力於爲Elastos系統的研發提供便利的持續集成功能:包括自動編譯、自動測試、文檔自動生成、開發人員代碼貢獻統計等。
(1)JDK 6
到Oracle官網下載相應版本的JDK 6。我將下載文件解壓到/usr/jdk6,執行如下命令:
編輯.bashrc文件:
sudo vim ~/.bashrc
在.bashrc中加入如下內容:
export JAVA_HOME=/usr/jdk6
export JRE_HOME=/usr/jdk6/jre
export CLASSPATH=/usr/jdk6/lib
export PATH=$PATH:$JAVA_HOME/bin
這樣JDK就算安裝成功了。這時候須要手動執行如下.bashrc腳本:
source ~/.bashrc
(2)Tomcat
運行Jenkins能夠使用其自帶的容器來啓動,也能夠部署到Tomcat下啓動。我的推薦後者。下面簡要描述一下Tomcat的安裝。
首先到Apache Tomcat官網下載對應版本的安裝包,我這裏選擇Core分類下的tar.gz包,將壓縮包解壓並重命名爲tomcat放到~目錄下,即/home/kurenai/tomcat 。
經過/home/kurenai/tomcat/bin/startup.sh就能開啓tomcat服務。相應的shutdown.sh可關閉tomcat服務。
爲了管理,咱們還須要添加tomcat管理用戶:
vim /home/kurenai/tomcat/conf/tomcat-users.xml
添加內容:
<user username=」your-username」 password=」your-password」 roles=」admin-gui,manager-gui」/>
這樣就能夠經過localhost:8080來訪問tomcat的管理界面了。
(3)Elastos的編譯環境配置
爲了在Ubuntu 64位系統中能夠編譯Elastos、Android2.3.5以及它的kernel2.6.29,須要安裝:
sudo apt-get install git-core gnupg flex bison gperf build-essential \
zip curl zlib1g-dev libc6-dev lib32ncurses5-dev ia32-libs \
x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev \
libgl1-mesa-dev g++-multilib mingw32 tofrodos python-markdown \
libxml2-utils xsltproc
(4)php5和mysql
php5和mysql的安裝能夠使用apt-get安裝,也可經過官網下載手動安裝。
sudo apt-get install php5
sudo apt-get install mysql-client mysql-server
sudo apt-get install php5-mysql
(5)Doxygen文檔自動生成工具的配置使用
首先到Doxygen官網http://www.doxygen.nl 下載安裝包。先安裝Doxygen所須要的組件和庫。使用命令:
sudo apt-get install graphviz perl bison flex qt4-dev-tools
安裝完畢後就能進行Doxygen的安裝:
tar –zxvf doxygen-…src.tar
./configure –prefix /path/to/doxygen –with-doxywizard
make && make install
若沒有使用prefix指定安裝路徑,則系統默認會把doxygen和doxywizard放在/usr/local/bin下,則無需添加環境變量,由於本路徑已經在path下了。doxywizard 是一個用來生成配置的圖形界面工具,與windows下的doxywizard相似。
安裝完畢後使用命令doxywizard即可經過圖形化的配置界面來生成Doxygen的doxyfile。
咱們選用的版本控制工具爲Git,在Ubuntu下能夠很輕鬆的安裝和使用它:
sudo apt-get install git git-core
等待安裝完畢就能夠了。惟一須要進行的配置是git使用時候的用戶名和郵箱,這是很重要的,涉及到後面代碼審覈Gerrit的使用。
使用如下命令來配置Git:
git config –global user.name 「your username」
git config –global user.email 「your e-mail」
從Gerrit官網下載Gerrit安裝包,爲war格式。使用如下指令初始化Gerrit:
java -jar gerrit.war -init -d /home/kurenai/gerrit_site
後面路徑爲安裝路徑。
而後會進入交互式的配置環節,大部分的配置能夠保留默認值,須要更改的配置下面進行說明:
Git代碼庫位置,要指向正確的Git庫位置,默認爲安裝目錄下的git,也能夠指定其餘目錄。Gerrit在啓動的時候經過掃描這個目錄來添加項目。
數據庫,選用mysql,數據庫的用戶名和密碼要設置正確不然會鏈接不上。
Gerrit的認證方式有OPENID,HTTP,LDAP等。
如果僅爲測試而已能夠使用development_become_any_account模式,該模式下第一個用戶爲超級用戶。
爲了使Gerrit可以發送郵件通知,須要配置郵件服務器。在[sendemail]選項下設置enable=true,smtpServer、smtpUser以及smtpPass就能使用郵件功能。
爲了使用Gerrit須要創建對應的Gerrit帳號和SSH密鑰對(注意這裏帳號的名稱和郵件名要和Git中的設置同樣)。經過Ubuntu的SSH工具便可。具體就不贅述了。
以上只是簡要介紹了Gerrit的架設,具體狀況請參考相關文檔。因爲本設計中的Elastos項目存儲在Elastos.org網站上的Gerrit服務器,所以咱們直接選用公司的Gerrit服務器做爲代碼倉庫,省去本身架設的步驟並且也更穩定。如下是代碼審覈服務器Gerrit的界面
圖4. 1基於代碼審覈服務器Gerrit的代碼倉庫
Jenkins做爲一款輕量級的持續集成服務器,其部署也至關簡單。到Jenkins官網下載對應的war包,放置到tomcat安裝目錄的webapps目錄下,而後重啓tomcat便可完成Jenkins的部署。能夠經過http://localhost/jenkins來訪問。
因爲Jenkins的默認根文件路徑是安裝用戶home下的.jenkins目錄,由於是隱藏文件不方便咱們查看。能夠經過如下方法修改默認路徑:
進入tomcat下的conf目錄,建立一個jenkins.xml文件,將以下幾行加入,
1 |
< Context docBase = "path/to/tomcat/webapps/jenkins.war" > |
2 |
< Environment name = "JENKINS_HOME" type = "java.lang.String" value = "/new/path/to/jenkins" override = "true" /> |
3 |
< Context > |
其中jenkins.war文件就是咱們放到webapps目錄下的jenkins文件,要給出這個文件存放的絕對路徑,value後面就是變動後jenkins的根目錄的位置。
反覆啓動tomcat後,修改tomcat/Webapps/jenkins/WEB-INF/web.xml
1 |
< env-entry > |
2 |
< env-entry-name >JENKINS_HOME</ env-entry-name > |
3 |
< env-entry-type >java.lang.String</ env-entry-type > |
4 |
< env-entry-value >/new/path/to/jenkins</ env-entry-value > |
5 |
</ env-entry > |
重啓tomcat,打開jenkins,jenkins根目錄修改完畢。
在部署完Jenkins後,咱們還須要對其進行必定的系統配置:
(1)進入Jenkins系統管理的系統設置部分:
須要對Git,Ant,E-mail,JDK進行設置。
Git 設置中的用戶名和郵箱與Git config中的設置一致;
Ant,JDK都可以使用自動在線安裝,方便slave機器的啓用。
E-mail設置較爲簡單就不贅述。
(2)Jenkins安全配置
點選「啓用安全」啓動Jenkins安全設置。這裏使用Jenkins專有用戶數據庫,受權策略使用Role-Based Strategy,這裏須要先安裝插件Role-based Authorization Strategy。
圖4. 6啓用安全
設定使用Role-Based Strategy後須要設置相應的Role來進行分配。這裏咱們設置一個擁有一切權利的管理員角色admin和只具備查看權限的readonly角色。admin角色勾選全部權限,readonly只勾選」read」選項。
圖4. 7角色設置(選項太多,這裏只列出部分)
而後進行角色分配:
圖4. 8分配角色
elautobuilder用戶爲管理員用戶(用戶註冊經過管理用戶來註冊),其餘匿名用戶爲只讀權限。
(3)Jenkins與Gerrit的鏈接配置
先安裝Gerrit trigger plugin。進行相應配置:
見: Jenkins學習筆記(五)之Gerrit trigger plugin
在引入自動化構建以前,開發人員須要天天自行下載最新代碼,進行編譯、測試、部署等重複的任務,不只繁瑣並且容易出錯,由於人畢竟不是機器。所以要實現持續集成的重點是實現自動化,包括自動檢測源代碼庫、自動化編譯、自動化測試、自動化部署。而要實現自動化,對於JAVA項目來講,ANT能夠說是如今的標準工具。它的默認配置文件時build.xml。
使用apt-get安裝ant,安裝方法:
sudo apt-get ant
使用的時候只須要將ant對應的build.xml構建腳本放在所要構建的項目根目錄下,經過執行指令:ant [target name] 便可,例如:ant clean debug ,將運行clean,debug目標。
Jenkins經過插件SSH Slave plugin和Credentials plugin能夠實現master/slave架構的集成服務機羣。
見:Jenkins學習筆記(四) master/slave的初步認識
見:Jenkins學習筆記(十一)如何構建和測試Android app
(1)建立任務
Elastos項目的自動編譯除了須要Elastos源代碼外還須要ElastosRDKforUbuntu源代碼,並須要將Elastos項目放置在ElastosRDKforUbuntu的Sources目錄下。能夠在Jenkins項目配置中使用自定義工做空間來實現。
這裏還須要設置Gerrit trigger,用來監視Gerrit的源碼倉庫變化。在項目配置的構建觸發器中選中Gerrit trigger,並添加對Elastos項目和ElastosRDKforUbuntu項目的監視。
(2)構建腳本
編譯Elastos項目的腳本使用main.sh,詳見附錄。
(3)構建結果斷定
Jenkins沒法經過main.sh的編譯結果來斷定編譯是否正確,這裏咱們須要自行使用Text Finder來查找編譯過程輸出中是否有」make: ***」字樣來斷定編譯正確與否。若出現該字樣,則將該構建定爲失敗構建。反之爲成功構建。
因爲與Gerrit進行了鏈接,當構建成功或者失敗後都能講其構建狀態反饋到Gerrit中。
見:jenkins 學習筆記(二)之自動文檔生成Doxygen
附錄另有用來實現Doxygen filter功能的filter程序。實現如下功能:
1)module { } 轉化成 module com.elastos {}
2)interface Name; 轉化成 Name interface;
3)在全部’}’後面添加’,即 ‘}’轉換成’};’
本文從傳統的軟件集成方式的發展出發,深刻研究了在軟件高速開發的現代軟件開發環境下的持續集成技術理論。並在該理論基礎上設計一套基於Jenkins的持續集成系統,並應用於Elastos項目的自動文檔生成和自動編譯工做。目標是提升軟件開發效率和質量。而在實踐中,能夠發現,引入持續集成技術後,對項目的開發起到了必定的幫助。
因爲本人對於持續集成理論的接觸時間較短,不少地方的理解不是很透徹。所以設計的繫系也存在不少問題。下面是我的對該系統之後完善的一點建議:
在項目的開發中,能夠使用Redmine實現Web化的項目管理,其中包括了項目Bug的跟蹤,新聞、wiki等。而如何將Jenkins與Redmine相結合,實現持續集成中Bug的持續跟蹤將會至關有意義。
持續集成中的自動測試每每是最費時間的,可是持續集成追求的是快速的集成構建,爲了知足這一點,能夠把構建分階段:第一階段是編譯和一些核心的無需進行數據庫交互的測試;第二階段是須要和數據庫進行交互的大量單元測試。若階段一構建成功則能視爲成功構建,而後再進行階段二測試,此時項目開發也能同時進行。提升集成效率。
當項目較多較大的時候,就有必要設置一個持續集成機器羣來進行高效的持續集成。而普通的master/slave架構沒法將項目構建過程拆分,從而併發執行。有必要研究如何實現將項目構建中可以併發執行的部分分發給多臺子機進行併發構建,從而下降構建時間。
[1] Steve McConnell.Daily build and Smoke Test[J].IEEE Software, 1996, 13(4):144-143
[2] LIU Qiao-Ling,FAN Bing-Bing,HUANG Xing-Ping.Research and Application of Continuous Integration Based on Hudson[J].Computer Systems& Applications,2010,19(12):151-154
[3] 劉華婷.基於Jenkins 快速搭建持續集成環境[DB/OL].(2011-11-24).
http://www.ibm.com/developerworks/cn/java/j-lo-jenkins/index.html
[4] 肖永鋒.基於J2EE的持續集成研究與應用[D].中山大學,2005
[5] Winston Royce. Managing the development of large software system[C].Proceedings,IEEE WESCON.1970
[6] 金敏,周翔編著.高級軟件開發過程—Rational統一過程、敏捷過程與微軟過程. 北京:清華大學出版社,2005
[7] 麥中凡,陶偉.微軟軟件開發解決方案框架 MSF.北京航空航天大學出版社,2003
[8] Continuous Integration[DB/OL].(2006-5-1)
http://www.martinfowler.com/articles/continuousIntegration.html
[9] 持續集成理論和實踐的新進展[DB/OL].(2011-7-25)
http://www.infoq.com/cn/articles/ci-theory-practice
[10] 徐仕成.持續集成在現代軟件開發中的應用與研究[D]. 中南大學,2007
[11] Alex Blewitt.GitGerrit and Jenkins/Hudson CI server[DB/OL].(2011-9-6).
http://www.infoq.com/cn/articles/Gerrit-jenkins-hudson
(1)main.sh 源代碼:
01 |
#!/bin/bash |
02 |
03 |
if [ -z $1 ]; then |
04 |
echo "Usage: main.sh [ option: checkout | update ]" |
05 |
echo "Option :" |
06 |
echo "checkout fetch new codes and make it" |
07 |
echo "update update a existent codes and make it" |
08 |
exit |
09 |
else |
10 |
export OPTION=$1 |
11 |
fi |
12 |
cd "$(dirname " $0 ")" |
13 |
export ELASTOS_DIR=$HOME /ElastosRDKforUbuntu |
14 |
export SCRIPT_DIR=$( pwd ) |
15 |
rm -f /tmp/dbg_compile_finish .txt |
16 |
XDK_VERSION = dbg |
17 |
$SCRIPT_DIR /compile .sh $XDK_VERSION $OPTION |
(2)compile.sh 源代碼:
01 |
#!/bin/bash |
02 |
03 |
[[ -z $1 ]] && echo "*ERROR* Please set Argument 1 [ dbg | rls ] !" && exit |
04 |
[[ -z $2 ]] && echo "*ERROR* Please set Argument 2 [ checkout | update | build ]" && exit |
05 |
06 |
export ELASTOS_DIR=$HOME /ElastosRDKforUbuntu |
07 |
08 |
chmod a+x $ELASTOS_DIR /Setup/ -R |
09 |
echo "Start to Compile Elastos" .$1 " ..." |
10 |
source $ELASTOS_DIR /Setup/SetEnv .sh arm_android && source chv.sh $1 |
11 |
12 |
if [ $2 == "update" ]; then |
13 |
echo "clobber..." |
14 |
emake.sh clobber |
15 |
fi |
16 |
17 |
cd Elastos && emake.sh |
18 |
19 |
if [ $XDK_VERSION == "dbg" ]; then |
20 |
echo "dbg_compile_finish" > /tmp/dbg_compile_finish .txt |
21 |
fi |
(3)car_filter.py 源代碼:
01 |
#!/usr/bin/python |
02 |
import getopt # get command-line options |
03 |
import os.path # getting extension from file |
04 |
import string # string manipulation |
05 |
import sys # output and stuff |
06 |
import re # for regular expressions |
07 |
08 |
#stream to write output to |
09 |
#outfile用來存儲處理完成後的輸出,供doxygen使用 |
10 |
outfile = sys.stdout |
11 |
12 |
#regular expression |
13 |
#須要識別的正則表達式,分別對應上面所說的三種轉化對象 |
14 |
re_interface = re. compile (r "(\s*)(interface)([^;]*)(?=;)" ) |
15 |
re_module = re. compile (r "(\s*)(module)(\s*)((?={)|(?=\s*$))" ) |
16 |
re_semicolon = re. compile (r "(.*)(})(.*)" ) |
17 |
#filters .car-files |
18 |
19 |
#在'}'後面添加';'的函數 |
20 |
def semicolonAdd(s): |
21 |
global re_semicolon |
22 |
match_semicolon = re_semicolon.match(s) |
23 |
if match_semicolon is not None : |
24 |
#found '}' |
25 |
return re_semicolon.sub(r "\1\2;\3" ,s) |
26 |
else : return s |
27 |
#對CAR文件進行處理的函數 |
28 |
def filterCAR(filename): |
29 |
global outfile |
30 |
global re_interface |
31 |
global re_module |
32 |
f = open (filename) |
33 |
r = f.readlines() |
34 |
f.close() |
35 |
#outfile.write("\n//processed by filterCAR \n") |
36 |
for s in r: |
37 |
#outfile.write(s+"\n") |
38 |
s = semicolonAdd(s) |
39 |
match_intface = re_interface.match(s) |
40 |
match_module = re_module.match(s) |
41 |
if match_intface is not None : |
42 |
#found interface |
43 |
outfile.write(re_interface.sub(r "\1\3 \2" ,s)) |
44 |
elif match_module is not None : |
45 |
#found module |
46 |
#outfile.write(match_module.group(0)+" com.elastos {\n") |
47 |
outfile.write(re_module.sub(r "\1\2 com.elastos" ,s)) |
48 |
else : |
49 |
#if it's no match just output |
50 |
outfile.write(s) |
51 |
# dumps the given file |
52 |
# 不作處理直接輸出 |
53 |
def dump(filename): |
54 |
f = open (filename) |
55 |
r = f.readlines() |
56 |
f.close() |
57 |
for s in r: |
58 |
sys.stdout.write(s) |
59 |
60 |
## main filter-function ## |
61 |
## |
62 |
## this function decides whether the file is |
63 |
## (*) car file |
64 |
## |
65 |
## and calls the appropriate function |
66 |
#主要filter函數,斷定是否爲.car文件,並調用適當函數進行相應處理 |
67 |
def filter (filename, out = sys.stdout): |
68 |
global outfile |
69 |
outfile = out |
70 |
try : |
71 |
root, ext = os.path.splitext(filename) |
72 |
if (ext.lower() = = ".car" ): |
73 |
## if it is a module call filterCAR |
74 |
filterCAR(filename) |
75 |
else : |
76 |
## if it is an unknown extension, just dump it |
77 |
dump(filename) |
78 |
sys.stderr.write( "OK\n" ) |
79 |
except IOError,e: |
80 |
sys.stderr.write(e[ 1 ] + "\n" ) |
81 |
## main-entry ## |
82 |
################ |
83 |
84 |
if len (sys.argv) ! = 2 : |
85 |
print "usage: " , sys.argv[ 0 ], " filename" |
86 |
sys.exit( 1 ) |
87 |
88 |
# Filter the specified file and print the result to stdout |
89 |
# doxygen會執行命令 <filter> <filter-file>,這裏使用sys.argv[1]取出<filter-file>的值並調用filter函數處理 |
90 |
filename = sys.argv[ 1 ] |
91 |
filter (filename) |
92 |
sys.exit( 0 ) |
整個程序並不難理解,關鍵點是三個正則表達式的使用,並把修改後的字符串寫到標準輸出流中,Doxygen會自動從中讀取,並進行文檔生成。
文章來源:
http://kurenai.elastos.org/2013/05/29/%E5%9F%BA%E4%BA%8Ejenkins%E7%9A%84%E8%87%AA%E5%8A%A8%E6%9E%84%E5%BB%BA%E7%B3%BB%E7%BB%9F%E5%BC%80%E5%8F%91/