2011/04/28

一種應用源碼管理的實作

這是之前 應用系統的版本管理 一文的實作, 目的是開源應用系統的版本管理。嘗試解決應用系統的客製化部份, 除了快速跟隨主要版本的提升, 同時也方便系統的繁殖 ... 預防天災(?)

這裡以 OFBiz r1096871 為例, 檔案有 {java:1436, xml:2626, groovy:454, properties:103, js:451, css:101, jar:391}, 它一直保持在更新的 狀態

面對必要的客製化, 過去常用上游分支 (vender branch) 手法處理, 以固定目錄版本管理為主, 實務上要面對許多細節。現在流行的分散式版本管理, 加上 rebase 大大改善舊有的方式。但分支有版本相依的特性, 而 OFBiz 的版本存檔 (snapshot) 就有 215mb 之譜 ... 要保存和轉移都負擔。

利用補丁管理(Patch Management)是不錯的主意, Mercurial 的 MQ 到 1.8 已經相當成熟。唯一問題是 OFBiz 使用 Apache 官方版本管理 Subversion, 由於版本存檔太大導致 hg-svn 掛點, 不得不生出對策。

因此, 題目變成上游是 svn (原本用 git, 簡化問題還是用 svn 示範), 實際處理用 hg 加 mq。

以自己流通的 mq 版本存檔為例, 大小約 100kb 左右(zip), svn 與對應 hg 則依需要而建。在 hg 功能的協助下, 能快速跟隨 trunk 版本更新, 而 mq 存檔小也利於保存和繁殖。(OFBiz 的 mq 範例放在 bitbucket )

但是實際運作起來, 操作有些瑣碎, 對象也繁多 ... 還好有 Fabric 加持簡化成三種操作, 得以省略一堆指令。

三種操作

  1. 初始 (init)
    拿到 mq 存檔, 加上 OFBiz Apache 上的 zip 檔 (附帶 .svn)。先把 OFBiz zip 檔解開有了 svn 儲存庫 (repository), 再更新與 mq 相同的 svn rev. 版本, 接著複製到 hg 儲存庫。

  2. 更新 (update)
    因應上游 trunk 更新, 把 svn 儲存庫與上游同步, 再更新 hg 儲存庫, 最後把 mq 做 rebase 處理。需要留意 OFBiz 會更新 *jar, 是不在 svn diff 服務範圍, 得由外部 diff 助拳。而後, 視情況對 mq 進行提交 (mqcommit), 或上送(mqpush)。

  3. mq變更 (mqpull)
    上游版本變更與驗證已完成, 並上送 bitbucket (第二個操作)。這時要對運作端進行更新, 先把新的 mq 取下, 依據新 mq 更新 svn 儲存庫, 同時更新對應 hg 儲存庫。


一般使用只要用 初始mq變更 就能保持版本換新, 僅在開發與測試需要 更新(mq commit/push) 的機制。

常見方式是: 只有開發與測試使用版本管理工具, 運作端用 rsync 之類工具同步, 符合標準 開發,
測試, 正式環境 分階段的開發週期。

用 svn-hg-mq 的好處是可從容面對應用系統會遇到的因地制宜 ... 如果不時在 正式環境 被要求改一點顯示文字或邏輯, 用此法就放手去改。然後以 mq commit 保存差異並列管, 之後再看看要怎麼處理, 同時也可放心進行上游版本更新(如果有的話)。

假使開發語言單一, 系統規模在一定範圍之內, 人力還是可以處理。而像 OFBiz 有 java, xml, groovy, ... 子系統多, 關連又盤根錯節, 就最好有固定的方式處理。

實際操作

在 OS X 10.6 + macports 與 Ubuntu 10.10 測試過。

要有 gcc, python, virtualenv, apple/sun jdk 6 (openjdk 6 還是無法使用 OFBiz)。因為 mercurial 1.8 和 fabric 1.0.1 都要用新版, 習慣用 virtualenv 來建, 這時得有 gcc 相關工具備著。


環境建立:
@ /w/proj
$ virutalenv --no-site-packages fab
$ cd fab
$ source bin/activate
(fab) $ pip install mercurial
...
(fab) $ pip install fabric
...
(fab) $ curl -O https://bitbucket.org/tcc/ofbiz-util/raw/38e378fef189/fabfile.py


準備 ~/.hgrc:
[ui]
username = jia@side.org
[extensions]
pager = 
hgext.mq = 
[pager]
pager = LESS='FSRX' less

注意 username, pager, mq 都要有 ... fabfile.py 會用到。


執行:
假設主要目錄是 /w/proj/fab/ofbiz, 會在下面自動建立 svn/, hg/, zip/ 三個目錄 ...
  1. svn/ 目錄為 svn 儲存庫, 和遠端 svn 同步。
  2. hg/ 目錄為 hg 儲存庫, 用來執行應用系統。和本地 svn/ 同步, 並且以 hg-mq 進行客製化處理。
  3. zip/ 目錄存放 ofbiz-trunk-current.zip 檔案, 只在 "初始" 步驟有用, 之後可刪除。
  • 進行初始儲存庫:
    @ /w/proj/fab
    $ source bin/activate
    (fab) $ fab init:/w/proj/fab/ofbiz
    ...
    就會進行, 由於部份操作挺費時間, 或須備妥網路, 像下載 ofbiz-trunk-current.zip 會停下來詢問, 若要執行到底:
    (fab) $ fab init:/w/proj/fab/ofbiz,auto=Y
    ...
    加上參數 auto=Y 即可。
  • 當 mq@bitbucket 有新版本要更新:
    (fab) $ fab mqpull:/w/proj/fab/ofbiz,sync=Y
    ...
    若沒有 sync=Y 就得手動進行 sync:
    (fab) $ fab sync:/w/proj/fab/ofbiz
    ...
目前 mq@bitbucket 沒有開放更新, 得自行建立 mq repository ... 修改 fabfile.py:
  1. 註解第 31 列 hg_mq_url = 'https://bitbucket.org/tcc/ofbiz-mq'。
  2. 打開第 32 列 hg_mq_url = 'file:///w/proj/ofbiz/mq2' 做必要修改。
然後與 trunk@OFBiz 同步:
(fab) $ fab update:/w/proj/fab/ofbiz
...
接著提交寫入, 並上送:
(fab) $ fab mqcommit:/w/proj/fab/ofbiz,push=Y
...
若沒下 push=Y, 要手動進行上送:
(fab) $ fab mqpush:/w/proj/fab/ofbiz
...

全部操作就這樣了。

建置 OFBiz 前先置入 hg-mq:
@/w/proj/fab/ofbiz/hg
(fab) $ hg qpush -a
...

然後按 OFBiz 安裝進行:
(fab) $ ./ant clean-all
...
(fab) $ ./ant run-install-extseed
...
(fab) $ ./ant create-admin-user-login
...
(fab) $ ./startofbiz.sh

...

如果要建立另一份系統做開發, 把目錄 /w/proj/fab/ofbiz/ 改為其他的, 例如 /w/proj/yi/side/ ... 依據客製 hg-mq 很快就能建立一套新的應用系統。不用辛辛苦苦裝完系統, 再逐一做客製相關設定。

試試看, 或許有更好的做法 :)

2011/04/20

oXygen XML 中文 PDF 輸出

一直用 oXygen 編輯器來處理 XML 相關檔案, 後來發覺寫文件的功能日益強大, 但輸出 PDF 有些障礙。也不是太大問題, 需要一些設定, 這裡的說明將包含 FO, Docbook, DITA。此外, 索引方面以 DITA 輸出為例, 示範更換 FO 處理器為 XEP 個人版。

以下環境是 OS X 10.6 加上 oXygen XML Editor 12.1。 請留意檔案位置, Windows 下注意 TTF 檔的差異。

另外, FO, Docbook, DITA 都有自由軟體套件, 協助編寫文件, 沒有 oXygen 編輯器也能運作。

FO 設定

  1. 產生字型規格檔, 參考: http://xmlgraphics.apache.org/fop/0.95/fonts.html

    假定把 FOP 1.0 安裝在 /w/j/x/fop-1.0 目錄。執行下列指令, 產生字型規格檔:

    $ export CL=/w/j/x/fop-1.0/build/fop.jar:/w/j/x/fop-1.0/lib/avalon-\
    framework.jar:/w/j/x/fop-1.0/lib/commons-logging.jar:/w/j/x/fop-\
    1.0/lib/commons-io.jar
    $ java -cp $CL org.apache.fop.fonts.apps.TTFReader \
    /Library/Fonts/Arial\ Unicode.ttf ArialUnicode.xml

    產生 ArialUnicode.xml, 放在 /w/proj/xml/fo/ArialUnicode.xml

  2. 建立 FOP 設定檔 userconfig.xml, 放在 /w/proj/xml/fo/userconfig.xml

    <fop version="1.0">
      <base>.</base>
      <renderers>
        <renderer mime="application/pdf">
          <filterList>
            <value>flate</value>
          </filterList>
          <fonts>
            <font metrics-url="file:///w/proj/xml/fo/ArialUnicode.xml" 
                embed-url="file:///Library/Fonts/Arial Unicode.ttf"
                kerning="yes">
              <font-triplet name="ArialUnicodeMS" style="normal"
               weight="normal"/>
              <font-triplet name="ArialUnicodeMS" style="normal"
               weight="bold"/>
              <font-triplet name="ArialUnicodeMS" style="italic"
               weight="normal"/>
              <font-triplet name="ArialUnicodeMS" style="italic"
               weight="bold"/>
              <font-triplet name="any" style="normal" weight="normal"/>
              <font-triplet name="any" style="normal" weight="bold"/>
            </font>
          </fonts>
        </renderer>
      </renderers>
      </fop>

    其中字型名稱 name="ArialUnicodeMS" 從 /w/proj/xml/fo/ArialUnicode.xml 裡頭的名稱參考而來。

  3. 修改 oXygen 設定 Preferences ➠ XML ➠ XSLT-FO-XQuery ➠ XQuery ➠ FO Processors

    找到 Configure file 項目改為 /w/proj/xml/fo/userconfig.xml

中文 FO 測試

  1. 編修原 oxygen/samples/fo/Miscellances/helloWorld.fo 改為 helloWorld-u8.fo:

    <?xml version="1.0" encoding="utf-8"?>
    <!-- Example from: http://www.renderx.net
      Copyright © 2004 RenderX, Inc.-->
    <fo:root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:fo="http://www.w3.org/1999/XSL/Format">
      <fo:layout-master-set>
        <fo:simple-page-master master-name="my-page">
          <fo:region-body margin="1in"/>
        </fo:simple-page-master>
      </fo:layout-master-set>
      <fo:page-sequence master-reference="my-page">
        <fo:flow flow-name="xsl-region-body" font-family="ArialUnicodeMS">
          <fo:block>Hello, world! 大家好!</fo:block>
        </fo:flow>
      </fo:page-sequence>
    </fo:root>
  2. 產生 PDF: 選單 Document ➠ Transformation ➠ Apply Transformation Senario 產生。

    或按 cmd + shift + T, 選擇 PDF (第一次要選 FO PDF)。

Docbook 設定

做妥上面 FO 設定。修改 oxygen/frameworks/docbook/xsl/fo/docbook_custom.xsl 在 </xsl:stylesheet> 前, <!-- end oXygen patch. --> 之後, 加上:

<!-- Traditional Chinese patch -->
<xsl:param name="body.font.family">ArialUnicodeMS</xsl:param>
<xsl:param name="body.font.size">12</xsl:param>
<xsl:param name="monospace.font.family">ArialUnicodeMS</xsl:param>
<xsl:param name="title.font.family">ArialUnicodeMS</xsl:param>
<!-- end Traditional Chinese patch -->

中文 Docbook 測試

  1. 修改 oxygen/samples/docbook/v5/sample.xml。Author 模式下, 在文字後加入中文, 例如:

    <sect1>
        <title>Inline Markup and Images 大家好</title>
  2. 產生 PDF, 同 FO 方式 ... cmd + shift + T 選擇 PDF (第一次要選 Docbook PDF)。

DITA 設定

  1. 修改 oxygen/frameworks/dita/DITA-OT/demo/fo/cfg/fo/font-mappings.xml

    找到以下字樣:

    <physical-font char-set="Simplified Chinese">
        <font-face>AdobeSongStd-Light</font-face>
    </physical-font>

    增加類似段落(共三處):

    <physical-font char-set="Traditional Chinese">
        <font-face>ArialUnicodeMS</font-face>
    </physical-font>
  2. 複製 oxygen/frameworks/dita/DITA-OT/demo/fo/cfg/fo/i18n/zh_CN.xml 成為同目下新檔 zh_TW.xml

    修改此 zh_TW.xml 內容, 把 <alphabet char-set="Simplified Chinese">...</alphabeat> 改為:

    <alphabet char-set="Traditional Chinese">
      <character-set>
        <character-range>
          <start include="yes">&#x0100;</start>
          <end include="yes">&#xff00;</end>
        </character-range>
      </character-set>
    </alphabet>

    很偷懶的方式, 需要修正。

  3. 修改 oxygen/frameworks/dita/DITA-OT/demo/fo/fop/conf/fop.xconf

    在 fop ☞ renderers ☞ renderer mime="application/pdf" ☞ fonts 下增加:

    <font metrics-url="file:///w/proj/xml/fo/ArialUnicode.xml"
        embed-url="file:///Library/Fonts/Arial Unicode.ttf" kerning="yes">
      <font-triplet name="ArialUnicodeMS" style="normal" weight="normal"/>
      <font-triplet name="ArialUnicodeMS" style="normal" weight="bold"/>
      <font-triplet name="ArialUnicodeMS" style="italic" weight="normal"/>
      <font-triplet name="ArialUnicodeMS" style="italic" weight="bold"/>
      <font-triplet name="any" style="normal" weight="normal"/>
      <font-triplet name="any" style="normal" weight="bold"/>
    </font>
  4. 建立 zh_TW 必要檔案, 在 oxygen/frameworks/dita/DITA-OT/demo/fo/cfg/common/ 下要有三個檔案:

    • index/zh_TW.xml

      複製 zh_CN.xml 修改, 先將 <language>zh-TW</language> 改為正確對應。下半部所有中文的 index.group 改為只有(也是需要修正):

      <index.group>
        <group.key>中文</group.key>
        <group.label>中文</group.label>
        <group.members>
          <char.set start-range="一" end-range="龤"/>
        </group.members>
      </index.group>
    • properties/zh_TW.properties

      chm.native.encoding=big5
      chm.project.language=0x404 Traditional Chinese
    • vars/zh_TW.xml

      複製修改, 可能必要的是 "Product Name"(顯示在 PDF 上方頁角), 其他隨意。

  5. 修改 oxygen/frameworks/dita/DITA-OT/demo/fo/build.xml 增加:

    <property name="document.locale" value="zh_TW"/>

    在 <property name="customization.dir ...> 上即可。

中文 DITA 測試

  1. 開 oxygen/dita/ 下某 DITA 專案, 開專案下的檔案在 Author 模式下修改, 增加中文字, 例如:

    <title>Changing the oil in your car 測試看看</title>
  2. 產生 PDF, 同 FO/Docbook 方式 ... cmd + shift + T 選擇 PDF (第一次要選 DITA Map PDF)。

安裝 XEP 個人版

FOP 1.0 還不支援索引(indexing)功能, 請參考 http://xmlgraphics.apache.org/fop/compliance.html#fo-object-indexing-section

XEP 個人版非商業用可取代 FOP 產生索引 http://www.renderx.com/download/personal.html

  1. 下載, 安裝到 /w/j/x/XEP/。

  2. 修改 /w/j/x/XEP/xep.xml 增加 (搜尋到 font-group):

    <font-group xml:base="file:/Users/tcchou/Library/Fonts/"
        label="Windows TrueType" embed="true" subset="true"> 
      <font-family name="ArialUnicodeMS">
        <font><font-data ttf="Arial Unicode.ttf"/></font>
      </font-family>
    </font-group>

    把 Arial Unicode.ttf 複製到個人字型目錄, 因為還有其他字型 ...

  3. oxygen 增加 XEP

    Preferences ➠ XML ➠ XSLT-FO-XQuery ➠ XQuery ➠ FO Processors

    點選 "If you have a custom XEP installation ..." 旁的 Browse 按鈕, 選擇 /w/j/x/XEP/xep 。

  4. 點選 "Configure Transformation Scenario", Duplicate "DITA Map PDF" 選擇 Processor: XEP 。

  5. 選擇 DITA 下專案(it-book 有 indexing 範例), 產生 PDF ... cmd + shift + T 。