Product deploy using NAnt and NSIS

参考网址

运行环境配置

解压缩附件NAnt和NSIS到一个固定目录(不能带空格的目录),例如:D:\Programs

配置 MSBUILD

将C:\WINDOWS\Microsoft.NET\Framework\v3.5加入环境变量

验证方式:命令行运行msbuild, 看到版本信息则为成功。

配置NAnt

将D:\Programs\NAnt\bin加入环境变量

验证方式:命令行运行nant, 看到版本信息则为成功。

配置NSIS

将D:\Programs\NSIS加入环境变量

验证方式:命令行运行makensis, 看到版本信息则为成功。

NAnt

ant是一个类似于bat和make的批处理工具,在.Net应用中称为NAnt。和其他工具不同的是,NAnt使用XML配置文件的形式作为工具的语言,更容易上手。详细介绍可参见http://nant.sourceforge.net

NAnt配置文件

NAnt的默认配置文件称为default.build(也可通过参数指定读取一个自定义的build文件),使用命令行进入 default.build所在的目录,直接执行nant,即可自动运行配置文件中的默认任务(target)。

<?xml version="1.0" encoding="utf-8" ?>
<project name="MySolution" default="deploy">
    <property name="build.dir" value="build" />
    <property name="deploy.dir" value="deploy" />
    <property name="nsis.script" value="deploy.nsi" />
    <property name="sln.dir" value="." />
    <property name="sln.name" value="MySolution.sln" />
    <property name="bin.dir" value="${sln.dir}\MySolution\bin\Release" />
    <target name="compile" description="compiles everything to release">
        <exec program="msbuild" commandline="${sln.dir}\${sln.name} /t:Rebuild /p:Configuration=Release" />
    </target>
    <target name="clean">
        <delete dir="${build.dir}" if="${directory::exists(build.dir)}"/>
        <delete dir="${deploy.dir}" if="${directory::exists(deploy.dir)}"/>
    </target>
    <target name="init" depends="clean" description="initial compilation setup">
        <mkdir dir="${build.dir}" />
        <mkdir dir="${deploy.dir}" />
    </target>
    <target name="rebuild" depends="compile, init">
        <copy todir="${build.dir}\MySolution">
            <fileset basedir="${bin.dir}">
                <exclude name="*.vshost.exe"/>
                <exclude name="*.vshost.exe.config"/>
                <include name="*.exe"/>
                <include name="*.dll"/>
                <include name="*.config"/>
            </fileset>
        </copy>
    </target>
    <target name="deploy" depends="rebuild">
        <exec program="makensis" commandline=' /X"SetCompressor /FINAL lzma" ${nsis.script}' />
    </target>
</project>

NAnt语法解释

设置项目名称,配置默认target。

<project name="MySolution" default="deploy">

定义属性名称,可以在下文中引用,例如"${sln.dir}\${sln.name}",效果等价于".\MySolution.sln"。

<property name="build.dir" value="build" />
<property name="deploy.dir" value="deploy" />
<property name="nsis.script" value="deploy.nsi" />
<property name="sln.dir" value="." />
<property name="sln.name" value="MySolution.sln" />
<property name="bin.dir" value="${sln.dir}\MySolution\bin\Release" />

定义一个名为compile的target,内容为执行msbuild,参数为".\MySolution.sln /t:Rebuild /p:Configuration=Release",这个任务表示Release编译MySolution.sln。之后在命令行中执行"nant compile",则会完成项目Release编译任务。

<target name="compile" description="compiles everything to release">
    <exec program="msbuild" commandline="${sln.dir}\${sln.name} /t:Rebuild /p:Configuration=Release" />
</target>

定义一个名为clean的target,内容为删除build和deploy这两个文件夹,如果文件夹存在的话。

<target name="clean">
    <delete dir="${build.dir}" if="${directory::exists(build.dir)}"/>
    <delete dir="${deploy.dir}" if="${directory::exists(deploy.dir)}"/>
</target>

定义一个名为init的target,这个任务依赖于clean任务,意思就是在执行init之前,会自动先执行clean任务。init任务内容是创建build和deploy文件夹。

<target name="init" depends="clean" description="initial compilation setup">
    <mkdir dir="${build.dir}" />
    <mkdir dir="${deploy.dir}" />
</target>

定义一个名为rebuild的target,这个任务依赖于先依赖于compile再依赖于init,那么在执行rebuile任务时,其实是按照 compile->init->rebuild的顺序执行。rebuild任务内容是将compile任务编译好的文件复制到 build\MySolution文件夹下,复制过程中只复制exe,dll,config,并且排除了 vshost.exe,vshost.exe.config文件。

<target name="rebuild" depends="compile, init">
    <copy todir="${build.dir}\MySolution">
        <fileset basedir="${bin.dir}">
            <exclude name="*.vshost.exe"/>
            <exclude name="*.vshost.exe.config"/>
            <include name="*.exe"/>
            <include name="*.dll"/>
            <include name="*.config"/>
        </fileset>
    </copy>
</target>

定义一个名为deploy的target,任务依赖于rebuild,它的最终执行顺序便是 compile->init->rebuild->deploy。任务内容是使用makensis命令进行程序打包。 commandline中的内容是makensis的运行参数,设置了打包的脚本文件名,打包的压缩算法,压缩级别,makensis的具体运行参数说明可参见http://nsis.sourceforge.net

<target name="deploy" depends="rebuild">
    <exec program="makensis" commandline=' /X"SetCompressor /FINAL lzma" ${nsis.script}' />
</target>

NSIS

NSIS(Nullsoft Scriptable Install System),它是一个脚本化的安装程序打包工具,它的优势在于支持脚本化配置安装程序打包,这样就有利于和其他部署工具配合使用。详细介绍可参见http://nsis.sourceforge.net

NSIS脚本

在上文中的NAnt中有说到makensis命令读取脚本文件进行打包。下面就是一个比较典型的程序打包脚本。

!include WordFunc.nsh
!insertmacro VersionCompare
!include LogicLib.nsh

!ifndef COMPRESS_DIR
!define COMPRESS_DIR ".\build"
!define TOOL_DIR     ".\tool"
!endif

!define PRODUCT_NAME_CN "测试程序"
!define PRODUCT_NAME_EN "MySolution"
!define PRODUCT_VERSION "V1.0"
!define PRODUCT_PUBLISHER_CN "上海金桥信息工程有限公司"
!define PRODUCT_PUBLISHER_EN "SHGBIT"
!define INSTALL_NAME "测试程序-${PRODUCT_VERSION}"

; The default installation directory
InstallDir $PROGRAMFILES\${PRODUCT_PUBLISHER_EN}\${PRODUCT_NAME_EN}

Name "${PRODUCT_NAME_EN}"
# name the installer
outFile ".\deploy\${INSTALL_NAME}.exe"
!include "MUI.nsh"

!define MUI_ICON ".\install-res\ico-inst.ico"
!define MUI_UNICON ".\install-res\ico-uninst.ico"
!define MUI_WELCOMEFINISHPAGE_BITMAP ".\install-res\side.bmp"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP ".\install-res\header.bmp"
;!define MUI_FINISHPAGE_RUN "$INSTDIR\xxx.exe"

;Install Pages (1-6)
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE ".\install-res\LICENSE"
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
;Uninstall Pages (1-2)
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES

;Languages
!insertmacro MUI_LANGUAGE "SimpChinese" # first language is the default language
# !insertmacro MUI_LANGUAGE "English"

BrandingText "${INSTALL_NAME}"
DirText "安装程序将安装 $(^NameDA) 在下列文件夹。要安装到不同文件夹,单击 [浏览(B)] 并选择其他的文件夹。 $_CLICK" 

Section "All Components " AllSection
    SetOutPath "$INSTDIR"
    File /r "${COMPRESS_DIR}\MySolution\*.*"
SectionEnd

Section -PostInstallSection
    WriteUninstaller "$INSTDIR\Uninstall.exe"
    CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME_EN}"
    CreateShortCut "$DESKTOP\${INSTALL_NAME}.lnk" "$INSTDIR\MySolution.exe"
    CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME_EN}\${INSTALL_NAME}.lnk" "$INSTDIR\MySolution.exe"
    CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME_EN}\卸载.lnk" "$INSTDIR\Uninstall.exe"
    CreateShortCut "$SMSTARTUP\${INSTALL_NAME}.lnk" "$INSTDIR\MySolution.exe"

    WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}" "DisplayName" "${PRODUCT_NAME_EN}"
    WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}" "UninstallString" "$INSTDIR\uninstall.exe"
    WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}" "DisplayIcon" "$INSTDIR\ico-inst.ico"
SectionEnd

Section Uninstall
    RMDir /r /REBOOTOK "$INSTDIR"
    RMDir /r /REBOOTOK "$SMPROGRAMS\${PRODUCT_NAME_EN}"
    Delete /REBOOTOK "$DESKTOP\${INSTALL_NAME}.lnk"
    Delete /REBOOTOK "$SMSTARTUP\${INSTALL_NAME}.lnk"

    DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}"
SectionEnd

Function .onInit
  !insertmacro MUI_LANGDLL_DISPLAY
FunctionEnd

Function .onInstSuccess
;    MessageBox MB_YESNO|MB_ICONQUESTION "安装完成,系统重启后才能生效,是否立即重启?" IDNO +2
;        Reboot
FunctionEnd 

Function un.onInit
  !insertmacro MUI_UNGETLANGUAGE
FunctionEnd

Function un.onUninstSuccess
;    MessageBox MB_YESNO|MB_ICONQUESTION "安装完成,系统重启后才能生效,是否立即重启?" IDNO +2
;        Reboot
FunctionEnd

NSIS脚本语法解释

符号说明

!XXXX     NSIS脚本的关键字
;和# NSIS脚本注释标记

定义COMPRESS_DIR和TOOL_DIR两个变量,用来保存目录位置

!ifndef COMPRESS_DIR
!define COMPRESS_DIR ".\build"
!define TOOL_DIR     ".\tool"
!endif

定义几个变量,用来保存程序名称,版本号,公司名称

!define PRODUCT_NAME_CN "测试程序"
!define PRODUCT_NAME_EN "MySolution"
!define PRODUCT_VERSION "V1.0"
!define PRODUCT_PUBLISHER_CN "上海金桥信息工程有限公司"
!define PRODUCT_PUBLISHER_EN "SHGBIT"

定义变量保存打包生成的安装程序的文件名

!define INSTALL_NAME "测试程序-${PRODUCT_VERSION}"

设置程序安装的默认目录,$PROGRAMFILES=X:\Program Files,是NSIS自带的变量

InstallDir $PROGRAMFILES\${PRODUCT_PUBLISHER_EN}\${PRODUCT_NAME_EN}

设置程序名称,这个名称将在安装包的标题栏上显示

Name "${PRODUCT_NAME_EN}"

设置生成安装包的具体路径

outFile ".\deploy\${INSTALL_NAME}.exe"

设置安装过程中显示的图片文件

!define MUI_ICON ".\install-res\ico-inst.ico"
!define MUI_UNICON ".\install-res\ico-uninst.ico"
!define MUI_WELCOMEFINISHPAGE_BITMAP ".\install-res\side.bmp"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP ".\install-res\header.bmp"

设置是否安装完成后运行程序

;!define MUI_FINISHPAGE_RUN "$INSTDIR\xxx.exe"

设置安装过程的步骤,下面定义了5个步骤,分别为欢迎、许可协议、设置安装目录、安装进度、完成安装。

!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE ".\install-res\LICENSE"
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH

设置卸载过程的步骤,下面定义了5个步骤,分别为卸载确认、卸载完成。

!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES

设置安装过程的语言选择界面,下面只定义了一种语言(简体中文)。

!insertmacro MUI_LANGUAGE "SimpChinese"
# first language is the default language#  !insertmacro MUI_LANGUAGE "English"

设置安装过程中界面下方虚线上写的名称

BrandingText "${INSTALL_NAME}"

设置安装过程中,选择安装目录阶段时显示的提示文字信息

DirText "安装程序将安装 $(^NameDA) 在下列文件夹。要安装到不同文件夹,单击 [浏览(B)] 并选择其他的文件夹。 $_CLICK"

Section有些相当于C#中Event的意思,下面这段表示在所有Section中设置输出路径为"$INSTDIR",设置需要打包的文件为"${COMPRESS_DIR}\MySolution\*.*",/r表示自动覆盖已存在文件。SetOutPath和File都是NSIS的内置函数,还有之前出现过的BrandingText、DirText之类的都是内置函数。

Section "All Components " AllSection
    SetOutPath "$INSTDIR"
    File /r "${COMPRESS_DIR}\MySolution\*.*"
SectionEnd

这是安装过程中文件复制阶段完成后的事件(注:并非点击完成按钮后整个安装过程结束时的事件),下面这段在事件里生成了uninstall.exe 程序,开始菜单添加了快捷方式,桌面添加了快捷方式,系统开机启动里添加了快捷方式,系统注册表中添加了软件安装信息(用于在控制面板的添加删除程序里找到MySolution这个软件)

Section -PostInstallSection
    WriteUninstaller "$INSTDIR\Uninstall.exe"
    CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME_EN}"
    CreateShortCut "$DESKTOP\${INSTALL_NAME}.lnk" "$INSTDIR\MySolution.exe"
    CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME_EN}\${INSTALL_NAME}.lnk" "$INSTDIR\MySolution.exe"
    CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME_EN}\卸载.lnk" "$INSTDIR\Uninstall.exe"
    CreateShortCut "$SMSTARTUP\${INSTALL_NAME}.lnk" "$INSTDIR\MySolution.exe"

    WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}" "DisplayName" "${PRODUCT_NAME_EN}"
    WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}" "UninstallString" "$INSTDIR\uninstall.exe"
    WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}" "DisplayIcon" "$INSTDIR\ico-inst.ico"
SectionEnd

这是程序卸载过程中文件删除阶段完成后的事件,下面这段根据之前的PostInstallSection中写的内容依次进行了删除,这里需要注意卸载过程的完整,否则就成了卸载不干净的垃圾软件了^.^。/r表示递归删除文件夹,/REBOOTOK表示如果文件被占用,则重启之后自动删除。

Section Uninstall
    RMDir /r /REBOOTOK "$INSTDIR"
    RMDir /r /REBOOTOK "$SMPROGRAMS\${PRODUCT_NAME_EN}"
    Delete /REBOOTOK "$DESKTOP\${INSTALL_NAME}.lnk"
    Delete /REBOOTOK "$SMSTARTUP\${INSTALL_NAME}.lnk"

    DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}"
SectionEnd

这是双击安装程序时的事件,这里设置为双击之后出现语言选择界面

Function .onInit
 !insertmacro MUI_LANGDLL_DISPLAY
FunctionEnd

这是安装程序退出时的事件,这里将多语言资源卸载

Function un.onInit
  !insertmacro MUI_UNGETLANGUAGE
FunctionEnd

这是安装成功的事件,可以在这个阶段弹出是否要重启的确定框。

Function .onInstSuccess
;    MessageBox MB_YESNO|MB_ICONQUESTION "安装完成,系统重启后才能生效,是否立即重启?" IDNO +2
;        Reboot
FunctionEnd

这是卸载成功的事件,可以在这个阶段弹出是否要重启的确定框。

Function un.onUninstSuccess
;    MessageBox MB_YESNO|MB_ICONQUESTION "安装完成,系统重启后才能生效,是否立即重启?" IDNO +2
;        Reboot
FunctionEnd
posted @ 2012-10-09 22:58  CanMusic  阅读(563)  评论(1编辑  收藏  举报