• Subversion 1.5 发布说明 at 2008年06月22日

    结果是,checkout 与 checkout --depth=infinity 相同,但是 switch 和 update 与 switch --depth=infinity 和 update --depth=infinity 不同,前者根据现存的 depth 值更新,而后者获取所有的内容。

    作为开始,可以使用--depth=empty 或--depth=files 选项 checkout 文件,如果需要额外的文件或目录,可以使用合适的--depth 选项的 update 命令来获取。除了其他的状态信息,svn status 必须列出目录周围的 depths。当调用的目录的 depth 不是缺省值(depth-infinity)时 svn info 命令也会列出其 depth。

    注意: 当前对于稀疏检出没有反选的接口—也就是说,在引入到工作拷贝后(尽管有一些相对简单的方法可以获取此目标),没有命令可以取消选择或 “折叠” 子目录,详细信息见 issue #2843。 与以前服务器的兼容性

    –depth 特性显然需要客户端是 1.5 以上的,也需要 1.5 以上的服务器才能最有效的工作,然而,客户端仍然需要在 1.4.x 服务器时工作正常;只是有较差的效率。

    这是因为以前的服务器不会理解—因而会忽略—不会清楚客户端说的 “depth” 的含义。所以当客户端请求比 depth-infinity 更浅的 depth,以前的服务器会返回比客户端需要更多的数据,然而 Subversion1.5+ 的客户端知道是与旧的服务器通话,并会过滤这些多余的数据,因此,操作会更长一些,因为服务器发送了许多客户端忽略的数据,但是最终在客户端产生的数据相同。(注意旧的服务器理解网络协议的 recurse,而 1.5+ 客户端根据 depth 发送标记;这减轻了额外的网络惩罚。) 进一步阅读

    * The Sparse Directories section in the Subversion book. * The design/implementation document in the repository.

    交互式冲突解决(客户端)

    在 update/switch/merge 子命令的操作中,现在冲突解决是使用交互式的命令行客户端完成,客户端库提供了一个 callback 函数,所以其他客户端也能以同样的方式工作。

    下面是使用命令行客户端例子:

    $ svn up U contrib/client-side/svnmerge/svnmerge_test.py Conflict discovered in 'contrib/client-side/svnmerge/svnmerge.py'. Select: (p) postpone, (df) diff-full, (e) edit, (s) show all options: s (p) postpone - mark the conflict to be resolved later (df) diff-full - show all changes made to merged file (e) edit - change merged file in an editor (r) resolved - accept merged version of file (mf) mine-full - accept my version of entire file (ignore their changes) (tf) theirs-full - accept their version of entire file (lose my changes) (l) launch - launch external tool to resolve conflict (s) show all - show this list

    Select: (p) postpone, (df) diff-full, (e) edit, (s) show all options: tf G contrib/client-side/svnmerge/svnmerge.py Updated to revision 25685. $

    这个特性可以使用–non-interactive 选择关闭,或者通过设置运行配置文件中的 “[miscellany] interactive-conflicts = no” 永久关闭。

    交互式冲突解决的 API 通过一个 callback 函数公开,并有如下数据类型:

    * svn_wc_conflict_resolver_func_t, callback API 本身 * svn_wc_conflict_description_t, 传递给 callback 的冲突描述 * svn_wc_conflict_action_t, 冲突描述中尝试工作内容的部分 * svn_wc_conflict_reason_t, 冲突描述中冲突类型部分 * svn_wc_conflict_result_t, 返回的冲突解决尝试结果 * svn_wc_conflict_choice_t, 用户选择动作的列表

    客户端通过设置他们的 svn_client_ctx_t 的 conflict_func 字段提供了他们的 callback 函数,并可以通过对应的 conflict_baton 字段提供额外的 callback 状态。 变更列表支持 (changelist)(客户端)

    Subversion 客户端现在包含了变更列表(changelist)的改变,一组与选定名称关联的文件,当工作在同一个工作拷贝的不同集合的文件时这样非常有效,Subversion1.5 允许你为每组文件关联一个变更列表,大多数可以将一组文件作为目标的命令现在也接受–changelist 选项,会根据 changelist 的成员过滤目标,变更列表的成员可以使用 changelist 子命令编辑。

    变更列表完全是客户端控制的。他们不会发送到服务器,对同一个版本库其他用户都不可见。另外,--changelist 选项不是添加剂;如果一个文件在没有--changelist 的时候加入到目标的列表,它也不会加入进去,它不会管 changelist 的成员。当前,一个文件一次只能属于一个变更列表,目录不能作为变更列表的成员。

    下面的子命令支持--changelist 选项:

    * changelist * commit * diff (only wc-wc and wc-repos cases) * info * propget * proplist * propset * propdel * revert * status * update

    进一步阅读

    * The Changelists section in the Subversion book. * The design/implementation document in the repository.

    svn:externals 中的相对 URL,peg revisions(客户端)

    对 svn:externals 特性的两个增强 对于 URL 的 Peg revision 语法

    兼容性和新的语法:由于兼容性原因,1.5 以前的 svn:externals 语法继续不理解 peg revisions,引入了一种支持 URL 中 peg revisions 的新语法。

    以前的格式是:

    foo [url]http://example.com/repos/zig/url][ foo/bar -r 1234 [url]http://example.com/repos/zag/url][

    不支持 peg revisions,如下的外部定义不能工作(除非目录名就是 zig@HEAD and zag@HEAD):

    foo [url]http://example.com/repos/zig@HEAD/url][ foo/bar -r 1234 [url]http://example.com/repos/zag@HEAD/url][

    新格式将跟在外部定义后面的路径 URL 移动到第一位;如果有一个操作(-r)修订版本,则在 URL 之前,下面是四个外部定义行:

    [url]http://example.com/repos/zig/url][ foo1 -r 1234 [url]http://example.com/repos/zag/url][ foo/bar1 [url]http://example.com/repos/zig@HEAD/url][ foo2 -r 1234 [url]http://example.com/repos/zag@HEAD/url][ foo/bar2

    换句话说,操作(“r”)和 peg(“@”)都是允许,但都不是必须的。 对相对 URL 的支持

    在 Subversion1.5 之前,svn:externals 中的 URL 必须是绝对路径,现在他们可以是相对的。现在支持四种相对外部引用。(在下面的例子里,假设我们有两种版本库:一个是在 [url]http://example.com/svn/repos-1/url][ ,另一个在 [url]http://example.com/svn/repos-2/url],我们检出 url] http://example.com/svn/repos-1/project1/trunk/url],而 svn:externals[ 设置为 trunk。)

    ../

    svn:externals 属性设置目录的相对路径,则 URL 是以../开始,例如:

    ../../project2/trunk common/project2/trunk

    这就是将 [url]http://example.com/svn/repos-1/project2/trunk/url][ 加入到 common/project2/trunk。外部 URL 相对于设置 svn:externals 属性的目录的 URL,而不是写到磁盘的外部的目录。 ^/

    相对于库的根。

    ^/project2/trunk common/project2/trunk

    这就是将 [url]http://example.com/svn/repos-1/project2/trunk/url] 加入到 common/project2/trunk。[

    你可以容易使用相对 URL 来引用其他的版本库:

    ^/../repos-2/foo/trunk common/foo/trunk

    就是 [url]http://example.com/svn/repos-2/foo/trunk/url] 加入到 common/foo/trunk。[ //

    相对于模式,这就是拷贝了检出或导出 URL 的模式到 svn:externals,当同一个主机必须依赖于网络位置按照不同的模式访问;例如局域网的客户端使用 http://,而外部客户使用 svn+ssh://。

    //example.com/svn/repos-1/project2/trunk common/project2/trunk

    这将会把 [url]http://example.com/svn/repos-1/project2/trunk/url] 提取到 common/project2/trunk,如果工作拷贝是通过 svn+ssh://example.com/svn/repos-1/project1/trunk[ 检出的,那么 URL 将会是 svn+ssh://example.com/svn/repos-1/project1/trunk。 /

    服务器 root 的相对 URL,这是检出或导出的模式和主机名的 URL 拷贝到 svn:externals。

    /svn/repos-1/project2/trunk common/project2/trunk

    这会提取 [url]http://example.com/svn/repos-1/project2/trunk/url] 到 common/project2/trunk。如果工作拷贝是从 svn+ssh://example.com/svn/repos-1/project1/trunk[ 检出,那么 URL 将会是 svn+ssh://example.com/svn/repos-1/project1/trunk。

    旧的 svn:externals 格式依然支持相对 URL(不会支持 peg revisions)。

    当 Subversion 见到不使用绝对 URL 的 externals ,会将第一个参数作为相对 URL,第二个作为目标目录。 进一步阅读

    See The svn:externals section of the Subversion Book. ra_svn 和 svnserve 的 Cyrus SASL 支持(服务器和客户端)

    来自 Wikipedia:“SASL 是网络协议的认证和数据安全框架,它将认证机制与应用协议解耦,从理论上讲,允许任何 SASL 支持的认证机制应用到使用 SASL 的应用协议上”

    在实践中,服务器发送会发送一组它支持的认证机制,客户端会根据客户端的支持选择一种认证机制,并通知服务器这个决定。之后,会有一些信息交换,直到成功或者失败发生,在后一种情况,允许客户端重新认证。

    svn:// 协议会一直支持这种类型的协商,然而只是实现了 CRAM-MD5 和 ANONYMOUS。Cyrus SASL 支持所有这些,此外,提供了其它如 DIGEST-MD5, OTP (One-Time Passwords), GSSAPI (used for Kerberos authentication), NTLM (NT LAN Manager), SRP (Secure Remote Password) 以及其他机制的支持。支持机制的准确列表依赖于 SASL 是如何编译的,有一些还有外置依赖,或不是缺省编译。另外,因为每种机制实际上是一个共享库,会在运行中加载,有许多分布的包位于核心库外单独存放。

    关于使用 1.5 并开启 SASL 与 1.5 前的客户端工作的更多信息请看兼容性部分,关于 Subversion 的 SASL 支持可以看 sasl.txt。 对于 FSFS 大规模开发的改进支持,通过 sharding(服务器)

    FSFS 文件系统后端在各自的文件存放每个修订版本,在 Subversion1.5 之前,所有的文件都存放在版本库一个普通的目录里,现在新创建的 FSFS 库会使用二级的目录树,每个目录最多 1000 个文件。这种版本库只能与 Subversion1.5 客户端兼容,但是当然, Subversion1.5 仍然可以使用以前格式的版本库,而没有问题。

    这样做的主要原因是允许修订数量能够超越文件系统的目录树的限制,当现代文件系统能够成支持每个目录有百万条目,它会变得很慢,而且管理工具会变得笨拙或失败。

    关于 FSFS sharding 的更多信息可以看这个 blog entry。

    svnadmin create 创建后,使用版本库之前,shard 大小可以通过编辑 “db/format” 中的 “layout sharded” 来调整。 改进的 FSFS 优化,通过不可变的文件隔离(服务器)

    FSFS 版本库永远不会在写入修订版本后进行修改,尽管最好让操作系统永远缓存所有的文件,某些文件系统(例如 NFS)缺省可以通过这种缓存获益,现在 FSFS 版本库为此将不变的文件存放在子目录 “db/revs” 和 “db/txn-protorevs”,这允许这些目录加载到开启缓存(在 Linux 可以看 nfs 部分的 “nocto”)的挂接点上。

    因为提交事务存放在 db/txn-protorevs” 而不是” db/transactions”,后者的目录不必在同一个挂接点,如果版本库存放在较慢的文件系统(例如 NFS),提交效率可以通过将目录移动到本地磁盘(使用符号链)改进。如果你在一个网络负载平衡器之后使用多个 svn 服务器,你必须配置负载平衡器在一个事务中转向到同一个服务器,这通常叫做 “客户端喜好”。 WebDAV 透明通过代理写(服务器)

    Subversion1.5 引入了 svnsync — 一提供从一个版本库复制内容到另一个版本库的工具。尽管很有用,但 svnsync 只能从一个版本库拖入修订版本,但是不能将额外的提交返回给 master。Subversion1.5 为 mod_dav_svn 添加了 WebDAV 代理支持,有效的使用 mod_dav_svn 允许双向的修订版本历史复制。

    所有的客户端与 slave 服务器交互,但是 slave 会透明的将所有的写活动传递给 master(根据需要重写数据),slave 实质上是只读的,但是它们本地都有一个完整的版本库,服务器分流 master 服务器的读压力,某些情况下非常可观。

    如果使用支持 HTTP DAV 的缓存代理,这个模型非常有好处,在这个情况下,每个 slave 可以对应所有对应的只读请求,而无需传递给 master 后端。 要求

    * Subversion 1.5 或更新的。 * Apache HTTP Server 2.2.0 或更高,并开启 mod_proxy(许多 mod_proxy 修正的 bug 没有回到 httpd 的 2.0 版本)

    实例配置

    参与者:

    * Slave → slave.example.com(可以很多) * Master → master.example.com(可能只有一个) * A WebDAV client (ra_neon, ra_serf 其他 WebDAV 客户端)

    客户端做:

    % svn co [url]http://slave.example.com/repos/slave//url][ ... % svn ci % ...etc...

    (客户端可以操作如常)

    每个 slave 配置:

    DAV svn SVNPath /my/local/copy/of/repos SVNMasterURI [url]http://master.example.com/repos/master//url][

    master 必须有一个 post-commit 钩子可以更新所有的 slave,一个例子使用 svnadmin dump/svnadmin load ,ssh 作为支持。svnsync 可以完成同样的事情。

    此外,如果 master 版本库支持锁定,锁定数据库需要通过 post-lock 和 post-unlock 保持同步,将 master 状态传递到 slave。(用户名保留作为读者的练习),如果不传递锁定信息,用户需要能够精确的检测是否有一个锁定 - 但是锁定会一直工作。

  • Ant+Subversion 总结 at 2008年06月22日

    姜晓东,dev2dev ID: jiangxd, 软件工程师,联络方式 [email] j2ee@hotmail.com[/email](MSN),800736(QQ)。 Blog: [url]http://blog.csdn.net/abigfrog/url][ 研究方向:软件架构,SOA,技术框架,开源,工作流,表现层技术

    转载自:[url]http://dev2dev.bea.com.cn/blog/jiangxd/200803/ant_subversion_svn_18_944.html/url][

  • Subversion 的其他属性 zz at 2008年06月22日

    举个例子,你有一个文档希望显示最后修改的日期,你需要麻烦每个作者提交之前做这件事情,同时会改变描述这部分细细的部分,但是迟早会有人忘记做这件事,不选择简单的告诉 Subversion 来执行替换 LastChangedDate 关键字的操作,在你的文档需要放置这个关键字的地方放置一个 keyword anchor,这个 anchor 只是一个格式为 $KeywordName$ 字符串。

    所有作为 anchor 出现在文件里的关键字是大小写敏感的:为了关键字的扩展,你必须使用正确的按顺序大写。你必须考虑 svn:keywords 的属性值也是大小写敏感—特定的关键字名会忽略大小写,但是这个特性已经被废弃了。

    Subversion 定义了用来替换的关键字列表,这个列表保存了如下五个关键字,有一些也包括了可用的别名:

    Date 这个关键字保存了文件最后一次在版本库修改的日期,看起来类似于 $Date: 2002-07-22 21:42:37 -0700 (Mon, 22 Jul 2002) $,它也可以用 LastChangedDate 来指定。

    Revision 这个关键字描述了这个文件最后一次修改的修订版本,看起来像 $Revision: 144 $,也可以通过 LastChangedRevision 或者 Rev 引用。

    Author 这个关键字描述了最后一个修改这个文件的用户,看起来类似 $Author: harry $,也可以用 LastChangedBy 来指定。

    HeadURL 这个关键字描述了这个文件在版本库最新的版本的完全 URL,看起来类似 $HeadURL: [url]http://svn.collab.net/repos/trunk/README/url][ $,可以缩写为 URL。

    Id 这个关键字是其他关键字一个压缩组合,它看起来就像 $Id: calc.c 148 2002-07-28 21:30:43Z sally $,可以解释为文件 calc.c 上一次修改的修订版本号是 148,时间是2002年7月28日,作者是 sally。

    只在你的文件增加关键字 anchor 不会做什么特别的事情,Subversion 不会尝试对你的文件内容执行文本替换,除非明确的被告知这样做,毕竟,你可以撰写一个文档 [31] 关于如何使用关键字,你希望 Subversion 不会替代你漂亮的关于不需要替换的关键字 anchor 实例!

    为了告诉 Subversion 是否替代某个文件的关键字,我们要再次求助于属性相关的子命令,当 svn:keywords 属性设置到一个版本化的文件,这些属性控制了那些关键字将会替换到那个文件。这个值是空格分隔的前面列表的名称或是别名列表。

    举个例子,假定你有一个版本化的文件 weather.txt,内容如下:

    Here is the latest report from the front lines. $LastChangedDate$ $Rev$ Cumulus clouds are appearing more frequently as summer approaches. 当没有 svn:keywords 属性设置到这个文件,Subversion 不会有任何特别操作,现在让我们允许 LastChangedDate 关键字的替换。

    $ svn propset svn:keywords "Date Author" weather.txt property 'svn:keywords' set on 'weather.txt' $ 现在你已经对 weather.txt 的属性作了修改,你会看到文件的内容没有改变(除非你之前做了一些属性设置),注意这个文件包含了 Rev 的关键字 anchor,但我们没有在属性值中包括这个关键字,Subversion 会高兴的忽略替换这个文件中的关键字,也不会替换 svn:keywords 属性中没有出现的关键字。

    关键字和虚假的差异

    用户可见的关键字替换会让你以为每一个具有此特性的文件的每个版本都会与前一个版本至少在关键字替换的地方不同,但是实际上并不是如此,当用 svn diff 检查本地修改时,或者是在使用 svn commit 传输修改之前,Subversion 不会 “取消替换” 任何上次替换的关键字,结果就是版本库保存的文件只保存用户实际做的修改。

    在你提交了属性修改后,Subversion 会立刻更新你的工作文件为新的替代文本,你将无法找到 $LastChangedDate$ 的关键字 anchor,你会看到替换的结果,这个结果也保存了关键字的名字,与美元符号($)绑定在一起,而且我们预测的,Rev 关键字不会被替换,因为我们没有要求这样做。

    注意我们设置 svn:keywords 属性为"Date Author",关键字 anchor 使用别名 $LastChangedDate$ 并且正确的扩展。

    Here is the latest report from the front lines. $LastChangedDate: 2002-07-22 21:42:37 -0700 (Mon, 22 Jul 2002) $ $Rev$ Cumulus clouds are appearing more frequently as summer approaches. 如果有其他人提交了 weather.txt 的修改,你的此文件的拷贝还会显示同样的替换关键字值—直到你更新你的工作拷贝,此时你的 weather.txt 重的关键字将会被替换来反映最新的提交信息。

    svn:eol-style 不像我们说过的版本化文件的 svn:mime-type 属性,Subversion 假定这个文件保存了可读的数据,一般来讲,Subversion 因为这个属性来判断一个文件是否可以用上下文区别报告,否则,对 Subversion 来说只是字节。

    这意味着缺省情况下,Subversion 不会关注任何行结束标记(end-of-line,EOL),不幸的是不同的操作系统在文本文件使用不同的行结束标志,举个例子,Windows 平台下的 A 编辑工具使用一对 SCII 控制字符—回车(CR)和一个移行(LF)。Unix 软件,只使用一个 LF 来表示一个行的结束。

    并不是所有操作系统的工具准备好了理解与本地行结束样式不一样的行结束格式,一个常见的结果是 Unix 程序会把 Windows 文件中的 CR 当作一个不同的字符(通常表现为^M),而 Windows 程序会把 Unix 文件合并为一个非常大的行,因为没有发现标志行结束的回车加换行(或者是 CRLF)字符。

    对外来 EOL 标志的敏感会让在各个操作系统分享文件的人们感到沮丧,例如,考虑有一个源代码文件,开发者会在 Windows 和 Unix 系统上编辑这个文件,如果所有的用户使用的工具可以展示文件的行结束,那就没有问题。

    但实践中,许多常用的工具不会正确的读取外来的 EOL 标志,或者是将文件的行结束转化为本地的样式,如果是前者,他需要一个外部的转化工具(如 dos2unix 或是他的伴侣,unix2dos)来准备需要编辑的文件。后一种情况不需要额外的准备工作,两种方法都会造成文件会与原来的文件在每一行上都不一样!在提交之前,用户有两个选择,或者选择用一个转化工具恢复文件的行结束样式,或者是简单的提交文件—包含新的 EOL 标志。

    这个情景的结局看起来像是要浪费时间对提交的文件作不必要的修改,浪费时间是痛苦的,但是如果提交修改了文件的每一行,判断那个文件是通过正常的方式修改的会是一件复杂的工作,bug 在那一行修正的?那一行引入了语法错误?

    这个问题的解决方案是 svn:eol-style 属性,当这个属性设置为一个正确的值,Subversion 使用它来判断针对行结束样式执行何种特殊的操作,而不会因为多种操作系统的每次提交发生震荡。正确的值有:

    native 这会导致保存 EOL 标志的文件使用 Subversion 运行的操作系统的本地编码,换句话说,如果一个 Windows 用户取出一个工作拷贝包含的一个文件有 svn:eol-style 的属性设置为 native,这个文件会使用 CRLF 的 EOL 标志,一个 Unix 用户取出相同的文件会看到他的文件使用 LF 的 EOL 标志。

    注意 Subversion 实际上使用 LF 的 EOL 标志,而不会考略操作系统,尽管这对用户来说是透明的。

    CRLF 这会导致这个文件使用 CRLF 序列作为 EOL 标志,不管使用何种操作系统。

    LF 这会导致文件使用 LF 字符作为 EOL 标志,不管使用何种操作系统。

    CR 这会导致文件使用 CR 字符作为 EOL 标志,不管使用何种操作系统。这种行结束样式不是很常见,它用在一些老的苹果机(Subversion 不会运行的机器上)。

    svn:externals svn:externals 属性保存了指导 Subversion 从一个或多个取出的工作拷贝移出目录的指示,关于这个关键字的更多信息,见 “外部定义” 一节。

    svn:special svn:special 是唯一一个不是用户直接设置和修改的 svn:属性,当 “特别的” 对象如一个对象链接计划加入到版本库,Subversion 会自动设置这个属性。版本库像普通文件一样保存 svn:special 对象,然而,当一个客户端在检出和更新操作时看到这个属性时,就会翻译这个文件的内容,并且将文件转化为特殊类型的对象,在 Subversion1.1 中,只有版本化的符号链接有这个属性附加,但在以后的版本中其它特殊的节点也有可能使用这个属性。

    注意:Windows 客户端不会有符号链接,因此会忽略含有 svn:special 声明为符号链的文件,在 Windows,用户会以一个工作拷贝中的版本化的文件作为结束。

    自动属性设置 属性是 Subversion 一个强大的特性,成为本章和其它章讨论的许多 Subversion 特性的关键组成部分—文本区别和合并支持、关键字替换、新行的自动转换等等。但是为了从属性得到完全的利益,他们必须设置到正确的文件和目录。不幸的是,在日常工作中很容易忘记这一步工作,特别是当没有设置属性不会引起明显的错误时(至少相对与未能添加一个文件到版本控制这种操作),为了帮助你在需要添加属性的文件上添加属性,Subversion 提供了一些简单但是有用的特性。

    当你使用 svn add 或是 svn import 准备加入一个版本控制的文件时,Subversion 会运行一个基本探测来检查文件是包括了可读还是不可读的内容,如果 Subversion 猜测错误,或者是你希望使用 svn:mime-type 属性更精确的设置—或许是 image/png 或者 application/x-shockwave-flash—你可以一直删除或编辑那个属性。

    Subversion 也提供了自动属性特性,允许你创建文件名到属性名称与值影射,这个影射在你的运行配置区域设置,它们会影响添加和导入操作,而且不仅仅会覆盖 Subversion 所有缺省的 MIME 类型判断操作,也会设置额外的 Subversion 或者自定义的属性。举个例子,你会创建一个影射文件说在任何时候你添加了一个 JPEG 文件—一些符合.jpg 的文件—Subversion 一定会自动设置它们的 svn:mime-type 属性为 image/jpeg。或者是任何匹配.cpp 的文件,必须把 svn:eol-style 设置为 native,并且 svn:keywords 设置为 Id。自动属性支持是 Subversion 工具箱中属性相关最垂手可得的工具,见 “config” 一节来查看更多的配置支持。

    转载自:[url]http://www.cnitblog.com/tilan/articles/21818.html/url][

  • Subversion 的其他属性 zz at 2008年06月22日

    修改修订版本的属性

    还记的这些未版本化的属性?你也可以使用 svn 命令修改这些属性。只需要添加--revprop 命令参数,并且说明希望修改属性的修订版本。因为修订版本是全局的,你不需要指定一个路径,只要你已经位于你希望修改属性的工作拷贝路径,举个例子,你希望修改一个存在版本的提交日志信息。 [27]

    $ svn propset svn:log '* button.c: Fix a compiler warning.' -r11 --revprop property 'svn:log' set on repository revision '11' $ 注意,修改这些未版本化的属性的能力一定要明确的添加给版本库管理员(见 “钩子脚本” 一节)。因为属性没有版本化,如果编辑的时候不小心,就会冒丢失信息的风险,版本库管理员可以设置方法来防范这种意外,缺省情况下,修改未版本化的属性是禁止的。

    就像文件内容,你的属性修改是本地修改,只有使用 svn commit 命令提交后才会保存到版本库中,属性修改也可以很容易的取消—svn revert 命令会恢复你的文件和目录为编辑前状态,包括内容、属性和其它的信息。另外,你可以使用 svn status 和 svn diff 接受感兴趣的文件和目录属性的状态信息。

    $ svn status calc/button.c M calc/button.c $ svn diff calc/button.c Property changes on: calc/button.c


    Name: copyright

    • (c) 2003 Red-Bean Software

    $ 注意 status 子命令显示的 M 在第二列而不是在第一列,这是因为我们修改了 calc/button.c 的属性,而不是它的文本内容,如果我们都修改了,我们也会看到 M 出现在第一列(见 “svn status” 一节)。

    属性冲突

    与文件内容一样,本地的属性修改也会同别人的提交冲突,如果你更新你的工作拷贝目录并且接收到有资源属性修改与你的修改冲突,Subversion 会报告资源处于冲突状态。

    % svn update calc M calc/Makefile.in C calc/button.c Updated to revision 143. $ Subversion 也会在冲突资源的同一个目录创建一个.prej 扩展名的文件,保存冲突的细节。你一定要检查这个文件的内容来决定如何解决冲突,在你解决冲突之前,你会在使用 svn status 时看到这个资源的输出的第二列是一个 C,提交本地修改的尝试会失败。

    $ svn status calc C calc/button.c ? calc/button.c.prej $ cat calc/button.c.prej prop 'linecount': user set to '1256', but update set to '1301'. $ 为了解决属性冲突,只需要确定冲突的属性保存了它们应该的值,然后使用 svn resolved 命令告诉 Subversion 你已经手工解决了问题。

    你也许已经注意到了 Subversion 在显示属性时的非标准方式。你还可以运行 svn diff 并且重定向输出来产生一个有用的补丁文件,patch 程序会忽略属性补丁—作为规则,它会忽略任何不理解的噪音。很遗憾,这意味着完全应用 svn diff 产生的补丁时,任何属性修改必须手工实施。

    就象你看到的,属性修改的出现并没有对典型的 Subversion 工作流有显著的影响,更新工作拷贝、检查文件和目录的状态、报告所作的修改和提交修改到版本库等等的工作方式完全与属性的存在与否无关。svn 程序有一些额外的子命令用来进行属性修改,但那是唯一显而易见不对称的命令。

    特别属性 Subversion 没有关于属性的特殊政策—你可以通过它们实现自己的目的。Subversion 只是要求你不要使用 svn:开头的命名空间作为属性名,这是 Subversion 自己使用的命名空间。实际上,Subversion 定义了某些特殊的属性,这些属性对它们所附加的文件和目录有特殊的影响。在本小节,我们会解开这个谜团,并且描述这些属性怎样让你的生活更加容易。

    svn:executable svn:executable 属性用来控制一个版本化的文件自动执行文件权限设定,这个属性没有特定的值—它只是说明一个 Subversion 可以保留的文件权限的期望值,删除这个属性会恢复操作系统对这些权限的完全控制。

    在多数操作系统,执行一个文件或命令的能力是由执行位管理的,这些位通常是关闭的,必须由用户显式的指定,这意味着你必须改变文件的执行位,然后更新你的工作拷贝,燃火如果你的文件成为更新的一部分,它的执行位会被关闭,所以 Subversion 提供了 svn:executable 这个属性来保持打开执行位。

    这个属性对于没有可执行权限位的文件系统无效,如 FAT32 和 NTFS。 [28] 也就是说,尽管它没有定义的值,在设置这个属性时,Subversion 会强制它的值为 *,最后,这个属性只对文件有效,目录无效。

    svn:mime-type svn:mime-type 属性为 Subversion 的许多目的服务,除了保存一个文件的多用途网际邮件扩展(MIME)分类以外,这个属性值也描述了一些 Subversion 自己使用的行为特性。

    举个例子,如果一个文件 svn:mime-type 属性设置为非文本的 MIME 类型(通常是那些不是 text/开头的类型,但也有例外),Subversion 会假定这个文件保存了二进制内容—也就是不可读的—数据。一个好处就是 Subversion 通常在更新到工作拷贝时提供了一个前后相关的以行为基础的修改合并,但是对于保存二进制数据的文件,没有 “行” 的概念,所以对这些文件,Subversion 不会在更新时尝试执行合并操作,相反,任何时候你在本地修改的一个二进制文件有了更新,你的文件会被重命名为.orig 为扩展名,然后 Subversion 保存一个新的工作拷贝文件,保存更新时得到的修改,但原来的文件名已经不是你自己的本地修改。这个行为模式是用来保护用户在对不可文本合并的文件尝试执行文本的合并时失败的情形。

    另外,如果 svn:mime-type 属性被设置,Subversion 的 Apache 模块会使用这个值来在 HTTP 头里输入 Content-type:,这给了 web 浏览器如何显示一个文件提供了至关重要的线索。

    svn:ignore 这个 svn:ignore 属性保存了一个 Subversion 特定操作忽略的文件模式列表,或许这个是最常用的属性,它可以与 global-ignores 运行配置选项配合使用(见 “config” 一节)来过滤 svn status、svn add 和 svn import 命令中操作的未版本化文件。

    svn:ignore 背后的基本原理很容易解释,Subversion 不会假定工作拷贝中的所有文件或子目录是版本控制的一部分,资源必须被显式的使用 svn add 或者 svn import 放到 Subversion 的管理控制之下,作为结果,经常有许多工作拷贝的资源并没有版本化。

    现在,svn status 命令会的显示会包括所有未纳入版本控制且没有用 global-ignores(或是内置的缺省值)过滤掉的文件和子目录,这样可以帮助用户查看是否忘记了把某些自愿加入到版本控制。

    但是 Subversion 不可能猜测到每个需要忽略的资源的名字,但是也有一些资源是所有特定版本库的工作拷贝都有忽略的,强制版本库的每个用户来添加这些模式到他们的运行配置区域不仅仅是一个负担,也会与用户取出的其他工作拷贝配置需要存在潜在的冲突。

    解决方案是保存的忽略模式必须对出现在给定目录和这个目录本身的资源是独立的,一个常见的例子就是一个未版本化资源对一个目录来说是唯一的,会出现在那个位置,包括程序编译的输出,或者是—用一个本书的例子—DocBook 的文件生成的 HTML、PDF 或者是 PostScript 文件。

    CVS 用户的忽略模式

    Subversion 的 svn:ignore 属性与 CVS 的.cvsignore 文件的语法和功能非常类似,实际上,如果你移植一个 CVS 的工作拷贝到 Subversion,你可以直接使用.cvsignore 作为 svn propset 输入文件参数:

    $ svn propset svn:ignore -F .cvsignore . property 'svn:ignore' set on '.' $ 但是 CVS 和 Subversion 处理忽略模式的方式有一些不同,这两个系统在不同的时候使用忽略模式,忽略模式应用的对象也由微小的不同,但是 Subversion 不会识别重置回到没有忽略模式的! 模式的使用。

    为了这个目的,svn:ignore 属性是解决方案,它的值是一个多行的文件模式集,一行一个模式,这个属性已经设置到这个你希望应用模式的目录。 [29] 举个例子,你的 svn status 有如下的输出:

    $ svn status calc M calc/button.c ? calc/calculator ? calc/data.c ? calc/debug_log ? calc/debug_log.1 ? calc/debug_log.2.gz ? calc/debug_log.3.gz 在这个例子里,你对 button.c 文件作了一些属性修改,但是你的工作拷贝也有一些未版本化的文件:你从源代码编译的最新的计算器程序是 data.c,一系列调试输出日志文件,现在你知道你的编译系统会编译生成计算器程序。 [30] 就像你知道的,你的测试组件总是会留下这些调试日志,这对所有的工作拷贝都是一样的,不仅仅使你的。你也知道你不会有兴趣在 svn status 命令中显示这些信息,所以使用 svn propedit svn:ignore calc 来为 calc 目录增加一些忽略模式,举个例子,你或许会添加如下的值作为 svn:ignore 属性:

    calculator debug_log* 当你添加完这些属性,你会在 calc 目录有一个本地修改,但是注意你的 svn status 输出有什么其他的不同:

    $ svn status M calc M calc/button.c ? calc/data.c 现在,所有多余的输出不见了!当然,这些文件还在工作拷贝中,Subversion 仅仅是不再提醒你它们的存在和未版本化。现在所有讨厌的噪音都已经删除了,你留下了更加感兴趣的项目—如你忘记添加到版本控制的源代码文件。

    如果想查看被忽略的文件,可以设置 Subversion 的--no-ignore 选项:

    $ svn status --no-ignore M calc/button.c I calc/calculator ? calc/data.c I calc/debug_log I calc/debug_log.1 I calc/debug_log.2.gz I calc/debug_log.3.gz svn add 和 svn import 也会使用这个忽略模式列表,这两个操作都包括了询问 Subversion 来开始管理一组文件和目录。比强制用户挑拣目录树中那个文件要纳入版本控制的方式更好,Subversion 使用忽略模式来检测那个文件不应该在大的迭代添加和导入操作中进入版本控制系统。

    svn:keywords Subversion 具备有添加关键字的能力—一些有用的,关于版本化的文件动态信息的片断—不必直接添加到文件本身。关键字通常会用来描述文件最后一次修改的一些信息,因为这些信息每次都有改变,更重要的一点,这是在文件修改之后,除了版本控制系统,对于任何处理完全保持最新的数据都是一场争论,作为人类作者,信息变得陈旧是不可避免的。

  • subversion 管理员的工具箱 at 2008年06月22日

    不过,这些都是可以改变的。如果转储时设置了--incremental 选项,svnadmin 会比较第一个转储的修订版本和版本库中前一个修订版本,就像对待其它转储的修订版本一样。转储时也是一样,转储文件中将仅包含第一个转储的修订版本的增量信息。这样的好处是,可以创建几个连续的小体积的转储文件代替一个大文件,比如:

    $ svnadmin dump myrepos --revision 0:1000 > dumpfile1 $ svnadmin dump myrepos --revision 1001:2000 --incremental > dumpfile2 $ svnadmin dump myrepos --revision 2001:3000 --incremental > dumpfile3 这些转储文件可以使用下列命令装载到一个新的版本库中:

    $ svnadmin load newrepos < dumpfile1 $ svnadmin load newrepos < dumpfile2 $ svnadmin load newrepos < dumpfile3 另一个有关的技巧是,可以使用--incremental 选项在一个转储文件中增加新的转储修订版本。举个例子,可以使用 post-commit 钩子在每次新的修订版本提交后将其转储到文件中。或者,可以编写一个脚本,在每天夜里将所有新增的修订版本转储到文件中。这样,svnadmin 的 dump 和 load 命令就变成了很好的版本库备份工具,万一出现系统崩溃或其它灾难性事件,它的价值就体现出来了。

    转储还可以用来将几个独立的版本库合并为一个版本库。使用 svnadmin load 的--parent-dir 选项,可以在装载的时候指定根目录。也就是说,如果有三个不同版本库的转储文件,比如 calc-dumpfile,cal-dumpfile,和 ss-dumpfile,可以在一个新的版本库中保存所有三个转储文件中的数据:

    $ svnadmin create /path/to/projects $ 然后在版本库中创建三个目录分别保存来自三个不同版本库的数据:

    $ svn mkdir -m "Initial project roots" \ file:///path/to/projects/calc \ file:///path/to/projects/calendar \ file:///path/to/projects/spreadsheet Committed revision 1. $ 最后,将转储文件分别装载到各自的目录中:

    $ svnadmin load /path/to/projects --parent-dir calc < calc-dumpfile … $ svnadmin load /path/to/projects --parent-dir calendar < cal-dumpfile … $ svnadmin load /path/to/projects --parent-dir spreadsheet < ss-dumpfile … $ 我们再介绍一下 Subversion 版本库转储数据的最后一种用途——在不同的存储机制或版本控制系统之间转换。因为转储数据的格式的大部分是可以阅读的,[16] 所以使用这种格式描述变更集(每个变更集对应一个新的修订版本)会相对容易一些。事实上,cvs2svn.py 工具(参见 “转化 CVS 版本库到 Subversion” 一节)正是将 CVS 版本库的内容转换为转储数据格式,如此才能将 CVS 版本库的数据导入 Subversion 版本库之中。

    版本库备份 尽管现代计算机的诞生带来了许多便利,但有一件事听起来是完全正确的—有时候,事情变的糟糕,很糟糕,动力损耗、网络中断、坏掉的内存和损坏的硬盘都是对魔鬼的一种体验,即使对于最尽职的管理员,命运也早已注定。所以我们来到了这个最重要的主题—怎样备份你的版本库数据。

    Subversion 版本库管理员通常有两种备份方式—增量的和完全的。我们在早先的章节曾经讨论过如何使用 svnadmin dump --incremental 命令执行增量备份(见 “版本库的移植” 一节),从本质上讲,这个方法只是备份了从你上次备份版本库到现在的变化。

    一个完全的版本库备份照字面上讲就是对整个版本库目录的复制(包括伯克利数据库或者文件 FSFS 环境),现在,除非你临时关闭了其他对版本库的访问,否则仅仅做一次迭代的拷贝会有产生错误备份的风险,因为有人可能会在并行的写数据库。

    如果是伯克利数据库,恼人的文档描述了保证安全拷贝的步骤,对于 FSFS 的数据,也有类似的顺序。我们有更好的选择,我们不需要自己去实现这个算法,因为 Subversion 开发小组已经为你实现了这些算法。Subversion 源文件分发版本的 tools/backup/目录有一个 hot-backup.py 文件。只要给定了版本库路径和备份路径,hot-backup.py—一个包裹了 svnadmin hotcopy 但更加智能的命令—将会执行必要的步骤来备份你的活动的版本库—不需要你首先禁止公共的版本库访问—而且之后会从你的版本库清理死掉的伯克利日志文件。

    甚至当你用了一个增量备份时,你也会希望有计划的运行这个程序。举个例子,你考虑在你的调度程序(如 Unix 下的 cron)里加入 hot-backup.py,或者你喜欢更加细致的备份解决方案,你可以让你的 post-commit 的钩子脚本执行 hot-backup.py(见 see “钩子脚本” 一节),这样会导致你的版本库的每次提交执行一次备份,只要在你的 hooks/post-commit 脚本里添加如下代码:

    (cd /path/to/hook/scripts; ./hot-backup.py ${REPOS} /path/to/backups &) 作为结果的备份是一个完全功能的版本库,当发生严重错误时可以作为你的活动版本库的替换。

    两种备份方式都有各自的优点,最简单的方式是完全备份,将会每次建立版本库的完美复制品,这意味着如果当你的活动版本库发生了什么事情,你可以用备份恢复。但不幸的是,如果你维护多个备份,每个完全的备份会吞噬掉和你的活动版本库同样的空间。

    增量备份会使用的版本库转储格式,在 Subversion 的数据库模式改变时非常完美,因此当我们升级 Subversion 数据库模式的时候,一个完整的版本库导出和导入是必须的,做一半工作非常的容易(导出部分),不幸的是,增量备份的创建和恢复会占用很长时间,因为每一次提交都会被重放。

    在每一种备份情境下,版本库管理员需要意识到对未版本化的修订版本属性的修改对备份的影响,因为这些修改本身不会产生新的修订版本,所以不会触发 post-commit 的钩子程序,也不会触发 pre-revprop-change 和 post-revprop-change 的钩子。 [17] 而且因为你可以改变修订版本的属性,而不需要遵照时间顺序—你可在任何时刻修改任何修订版本的属性—因此最新版本的增量备份不会捕捉到以前特定修订版本的属性修改。

    通常说来,在每次提交时,只有妄想狂才会备份整个版本库,然而,假设一个给定的版本库拥有一些恰当粒度的冗余机制(如每次提交的邮件)。版本库管理员也许会希望将版本库的热备份引入到系统级的每夜备份,对大多数版本库,归档的提交邮件为保存资源提供了足够的冗余措施,至少对于最近的提交。但是它是你的数据—你喜欢怎样保护都可以。

    通常情况下,最好的版本库备份方式是混合的,你可以平衡完全和增量备份,另外配合提交邮件的归档,Subversion 开发者,举个例子,在每个新的修订版本建立时备份 Subversion 的源代码版本库,并且保留所有的提交和属性修改通知文件。你的解决方案类似,必须迎合你的需要,平衡便利和你的偏执。然而这些不会改变你的硬件来自钢铁的命运。[18] 这一定会帮助你减少尝试的时间。


    [13] 顺便说一句,这是 Subversion 的特性,而不是 bug。

    [14] 尽管 svnadmin dump 对是否以斜线作为路径的开头有统一的规定——这个规定就是不以斜线作为路径的开头——其它生成转储文件的程序不一定会遵守这个规定。

    [15] 比如:硬盘 + 大号电磁铁 = 毁灭。

    [16] Subversion 版本库的转储文件格式类似于 RFC-822 格式,后者广泛的应用于电子邮件系统中。

    [17] svnadmin setlog 可以被绕过钩子程序被调用。

    [18] 你知道的—只是对各种变化莫测的问题的统称。

    转载自:[url]http://www.cnitblog.com/tilan/articles/21817.html/url][

  • subversion 管理员的工具箱 at 2008年06月22日

    简言之,作出事务清理的决定前应该仔细考虑一下。许多信息源—比如 Apache 的错误和访问日志,已成功完成的 Subversion 提交日志等等—都可以作为决策的参考。管理员还可以直接和那些似乎已经死亡事务的提交者直接交流(比如通过邮件),来确认该事务确实已经死亡了。

    管理磁盘空间 虽然存储器的价格在过去的几年里以让人难以致信的速度滑落,但是对于那些需要对大量数据进行版本管理的管理员们来说,磁盘空间的消耗依然是一个重要的因素。版本库每增加一个字节都意味着需要多一个字节的磁盘空间进行备份,对于多重备份来说,就需要消耗更多的磁盘空间。Berkeley DB 版本库的主要存储机制是基于一个复杂的数据库系统建立的,因此了解一些数据性质是有意义的,比如哪些数据必须保留。哪些数据需要备份、哪些数据可以安全的删除等等。本节的内容专注于 Berkeley DB 类型的版本库。FSFS 类型的版本库不需要进行数据清理和回收。

    目前为止,Subversion 版本库中耗费磁盘空间的最大凶手是日志文件,每次 Berkeley DB 在修改真正的数据文件之前都会进行预写入(pre-writes)操作。这些文件记录了数据库从一个状态变化到另一个状态的所有动作——数据库文件反应了特定时刻数据库的状态,而日志文件则记录了所有状态变化的信息。因此,日志文件会以很快的速度膨胀起来。

    幸运的是,从版本 4.2 开始,Berkeley DB 的数据库环境无需额外的操作即可删除无用的日志文件。如果编译 svnadmin 时使用了高于 4.2 版本的 Berkeley DB,那么由此 svnadmin 程序创建的版本库就具备了自动清除日志文件的功能。如果想屏蔽这个功能,只需设置 svnadmin create 命令的--bdb-log-keep 选项即可。如果创建版本库以后想要修改关于此功能的设置,只需编辑版本库中 db 目录下的 DB_CONFIG 文件,注释掉包含 set_flags DB_LOG_AUTOREMOVE 内容的这一行,然后运行 svnadmin recover 强制设置生效就行了。查阅 “Berkeley DB 配置” 一节获得更多关于数据库配置的帮助信息。

    如果不自动删除日志文件,那么日志文件会随着版本库的使用逐渐增加。这多少应该算是数据库系统的特性,通过这些日志文件可以在数据库严重损坏时恢复整个数据库的内容。但是一般情况下,最好是能够将无用的日志文件收集起来并删除,这样就可以节省磁盘空间。使用 svnadmin list-unused-dblogs 命令可以列出无用的日志文件:

    $ svnadmin list-unused-dblogs /path/to/repos /path/to/repos/log.0000000031 /path/to/repos/log.0000000032 /path/to/repos/log.0000000033

    $ svnadmin list-unused-dblogs /path/to/repos | xargs rm

    disk space reclaimed!

    为了尽可能减小版本库的体积,Subversion 在版本库中采用了增量化技术(或称为 “增量存储技术”)。增量化技术可以将一组数据表示为相对于另一组数据的不同。如果这两组数据十分相似,增量化技术就可以仅保存其中一组数据以及两组数据的差别,而不需要同时保存两组数据,从而节省了磁盘空间。每次一个文件的新版本提交到版本库,版本库就会将之前的版本(之前的多个版本)相对于新版本做增量化处理。采用了这项技术,版本库的数据量大小基本上是可以估算出来的—主要是版本化的文件的大小—并且远小于 “全文” 保存所需的数据量。

    注意 由于 Subversion 版本库的增量化数据保存在单一 Berkeley DB 数据库文件中,减少数据的体积并不一定能够减小数据库文件的大小。但是,Berkeley DB 会在内部记录未使用的数据库文件区域,并且在增加数据库文件大小之前会首先使用这些未使用的区域。因此,即使增量化技术不能立杆见影的节省磁盘空间,也可以极大的减慢数据库的膨胀速度。

    版本库的恢复 “Berkeley DB” 一节中曾提到,Berkeley DB 版本库如果没有正常关闭可能会进入冻结状态。这时,就需要管理员将数据库恢复到正常状态。

    Berkeley DB 使用一种锁机制保护版本库中的数据。锁机制确保数据库不会同时被多个访问进程修改,也就保证了从数据库中读取到的数据始终是稳定而且正确的。当一个进程需要修改数据库中的数据时,首先必须检查目标数据是否已经上锁。如果目标数据没有上锁,进程就将它锁上,然后作出修改,最后再将锁解除。而其它进程则必须等待锁解除后才能继续访问数据库中的相关内容。

    在操作 Subversion 版本库的过程中,致命错误(如内存或硬盘空间不足)或异常中断可能会导致某个进程没能及时将锁解除。结果就是后端的数据库系统被 “塞住” 了。一旦发生这种情况,任何访问版本库的进程都会挂起(每个访问进程都在等待锁被解除,但是锁已经无法解除了)。

    首先,如果你的版本库出现这种情况,没什么好惊慌的。Berkeley DB 的文件系统采用了数据库事务、检查点以及预写入日志等技术来取保只有灾难性的事件 [15] 才能永久性的破坏数据库环境。所以虽然一个过于稳重的版本库管理员通常都会按照某种方案进行大量的版本库离线备份,不过不要急着通知你的管理员进行恢复。

    然后,使用下面的方法试着 “恢复” 你的版本库:

    确保没有其它进程访问(或者试图访问)版本库。对于网络版本库,关闭 Apache HTTP 服务器是个好办法。

    成为版本库的拥有者和管理员。这一点很重要,如果以其它用户的身份恢复版本库,可能会改变版本库文件的访问权限,导致在版本库 “恢复” 后依旧无法访问。

    运行命令 svnadmin recover /path/to/repos。 输出如下:

    Repository lock acquired。 Please wait; recovering the repository may take some time...

    Recovery completed. The latest repos revision is 19. 此命令可能需要数分钟才能完成。

    重新启动 Subversion 服务器。

    这个方法能修复几乎所有版本库锁住的问题。记住,要以数据库的拥有者和管理员的身份运行这个命令,而不一定是 root 用户。恢复过程中可能会使用其它数据存储区(例如共享内存区)重建一些数据库文件。如果以 root 用户身份恢复版本库,这些重建的文件拥有者将变成 root 用户,也就是说,即使恢复了到版本库的连接,一般的用户也无权访问这些文件。

    如果因为某些原因,上面的方法没能成功的恢复版本库,那么你可以做两件事。首先,将破损的版本库保存到其它地方,然后从最新的备份中恢复版本库。然后,发送一封邮件到 Subversion 用户列表(地址是:<[email] users@subversion.tigris.org[/email]>),写清你所遇到的问题。对于 Subversion 的开发者来说,数据安全是最重要的问题。

    版本库的移植 Subversion 文件系统将数据保存在许多数据库表中,而这些表的结构只有 Subversion 开发者们才了解(也只有他们才感兴趣)不过,有些时候我们会想到把所有的数据(或者一部分数据)保存在一个独立的、可移植的、普通格式的文件中。Subversion 通过 svnadmin 的两个子命令 dump 和 load 提供了类似的功能。

    对版本库的转储和装载的需求主要还是由于 Subversion 自身处于变化之中。在 Subversion 的成长期,后端数据库的设计多次发生变化,这些变化导致之前的版本库出现兼容性问题。当然,将 Berkeley DB 版本库移植到不同的操作系统或者 CPU 架构上,或者在 Berkeley DB 和 FSFS 后端之间进行转化也需要转储和装载功能。按照下面的介绍,只需简单几步就可以完成数据库的移植:

    使用当前版本的 svnadmin 将版本库转储到文件中。

    升级 Subversion。

    移除以前的版本库,并使用新版本的 svnadmin 在原来版本库的位置建立空的版本库。

    还是使用新版本的 svnadmin 从转储文件中将数据装载到新建的空版本库中。

    记住从以前的版本库中复制所有的定制文件到新版本库中,包括 DB_CONFIG 文件和钩子脚本。最好阅读一下新版本的 release notes,看看此次升级是否会影响钩子和配置选项。

    如果移植的同时改变的版本库的访问地址(比如移植到另一台计算机或者改变了访问策略),那么可以通知用户运行 svn switch --relocate 来切换他们的工作副本。参见 svn switch。

    svnadmin dump 命令会将版本库中的修订版本数据按照特定的格式输出到转储流中。转储数据会输出到标准输出流,而提示信息会输出到标准错误流。这就是说,可以将转储数据存储到文件中,而同时在终端窗口中监视运行状态。例如:

    $ svnlook youngest myrepos 26 $ svnadmin dump myrepos > dumpfile

    • Dumped revision 0.
    • Dumped revision 1.
    • Dumped revision 2. …
    • Dumped revision 25.
    • Dumped revision 26. 最后,版本库中的指定的修订版本数据被转储到一个独立的文件中(在上面的例子中是 dumpfile)。注意,svnadmin dump 从版本库中读取修订版本树与其它 “读者”(比如 svn checkout)的过程相同,所以可以在任何时候安全的运行这个命令。

    另一个命令,svnadmin load,从标准输入流中读取 Subversion 转储数据,并且高效的将数据转载到目标版本库中。这个命令的提示信息输出到标准输出流中:

    $ svnadmin load newrepos < dumpfile <<< Started new txn, based on original revision 1 * adding path : A ... done. * adding path : A/B ... done. … ------- Committed new rev 1 (loaded from original rev 1) >>>

    <<< Started new txn, based on original revision 2 * editing path : A/mu ... done. * editing path : A/D/G/rho ... done.

    ------- Committed new rev 2 (loaded from original rev 2) >>>

    <<< Started new txn, based on original revision 25 * editing path : A/D/gamma ... done.

    ------- Committed new rev 25 (loaded from original rev 25) >>>

    <<< Started new txn, based on original revision 26 * adding path : A/Z/zeta ... done. * editing path : A/mu ... done.

    ------- Committed new rev 26 (loaded from original rev 26) >>>

    既然 svnadmin 使用标准输入流和标准输出流作为转储和装载的输入和输出,那么更漂亮的用法是(管道两端可以是不同版本的 svnadmin:

    $ svnadmin create newrepos $ svnadmin dump myrepos | svnadmin load newrepos 默认情况下,转储文件的体积可能会相当庞大——比版本库自身大很多。这是因为在转储文件中,每个文件的每个版本都以完整的文本形式保存下来。这种方法速度很快,而且很简单,尤其是直接将转储数据通过管道输入到其它进程中时(比如一个压缩程序,过滤程序,或者一个装载进程)。不过如果要长期保存转储文件,那么可以使用--deltas 选项来节省磁盘空间。设置这个选项,同一个文件的数个连续修订版本会以增量式的方式保存—就像储存在版本库中一样。这个方法较慢,但是转储文件的体积则基本上与版本库的体积相当。

    之前我们提到 svnadmin dump 输出指定的修订版本。使用--revision 选项可以指定一个单独的修订版本,或者一个修订版本的范围。如果忽略这个选项,所有版本库中的修订版本都会被转储。

    $ svnadmin dump myrepos --revision 23 > rev-23.dumpfile $ svnadmin dump myrepos --revision 100:200 > revs-100-200.dumpfile Subversion 在转储修订版本时,仅会输出与前一个修订版本之间的差异,通过这些差异足以从前一个修订版本中重建当前的修订版本。换句话说,在转储文件中的每一个修订版本仅包含这个修订版本作出的修改。这个规则的唯一一个例外是当前 svnadmin dump 转储的第一个修订版本。

    默认情况下,Subversion 不会把转储的第一个修订版本看作对前一个修订版本的更改。 首先,转储文件中没有比第一个修订版本更靠前的修订版本了!其次,Subversion 不知道装载转储数据时(如果真的需要装载的话)的版本库是什么样的情况。为了保证每次运行 svnadmin dump 都能得到一个独立的结果,第一个转储的修订版本默认情况下会完整的保存目录、文件以及属性等数据。

  • subversion 管理员的工具箱 at 2008年06月22日

    警告 如果你打算通过手工编辑转储文件来移除一个顶级目录,注意不要让你的编辑器将换行符转换为本地格式(比如将\r\n 转换为\n)。否则文件的内容就与所需的格式不相符,这个转储文件也就失效了。

    剩下的工作就是创建三个新的版本库,然后将三个转储文件分别导入:

    $ svnadmin create calc; svnadmin load calc < calc-dumpfile <<< Started new transaction, based on original revision 1 * adding path : Makefile ... done. * adding path : button.c ... done. … $ svnadmin create calendar; svnadmin load calendar < cal-dumpfile <<< Started new transaction, based on original revision 1 * adding path : Makefile ... done. * adding path : cal.c ... done. … $ svnadmin create spreadsheet; svnadmin load spreadsheet < ss-dumpfile <<< Started new transaction, based on original revision 1 * adding path : Makefile ... done. * adding path : ss.c ... done. … $ svndumpfilter 的两个子命令都可以通过选项设定如何处理 “空” 修订版本。如果某个指定的修订版本仅包含路径的更改,过滤器就会将它删除,因为当前为空的修订版本通常是无用的甚至是让人讨厌的。为了让用户有选择的处理这些修订版本,svndumpfilter 提供了以下命令行选项:

    --drop-empty-revs 不生成任何空修订版本,忽略它们。

    --renumber-revs 如果空修订版本被剔除(通过使用--drop-empty-revs 选项),依次修改其它修订版本的编号,确保编号序列是连续的。

    --preserve-revprops 如果空修订版本被保留,保持这些空修订版本的属性(日志信息,作者,日期,自定义属性,等等)。如果不设定这个选项,空修订版本将仅保留初始时间戳,以及一个自动生成的日志信息,表明此修订版本由 svndumpfilter 处理过。

    尽管 svndumpfilter 十分有用,能节省大量的时间,但它却是把不折不扣的双刃剑。首先,这个工具对路径语义极为敏感。仔细检查转储文件中的路径是不是以斜线开头。也许 Node-path 和 Copyfrom-path 这两个头参数对你有些帮助。

    … Node-path: spreadsheet/Makefile … 如果这些路径以斜线开头,那么你传递给 svndumpfilter include 和 svndumpfilter exclude 的路径也必须以斜线开头(反之亦然)。如果因为某些原因转储文件中的路径没有统一使用或不使用斜线开头,[14] 也许需要修正这些路径,统一使用斜线开头或不使用斜线开头。

    此外,复制操作生成的路径也会带来麻烦。Subversion 支持在版本库中进行复制操作,也就是复制一个存在的路径,生成一个新的路径。问题是,svndumpfilter 保留的某个文件或目录可能是由某个 svndumpfilter 排除的文件或目录复制而来的。也就是说,为了确保转储数据的完整性,svndumpfilter 需要切断这些复制自被排除路径的文件与源文件的关系,还要将这些文件的内容以新建的方式添加到转储数据中。但是由于 Subversion 版本库转储文件格式中仅包含了修订版本的更改信息,因此源文件的内容基本上无法获得。如果你不能确定版本库中是否存在类似的情况,最好重新考虑一下到底保留/排除哪些路径。

    svnshell.py Subversion 源代码树中有一个类似于 shell 的版本库访问界面。Python 脚本 svnshell.py(位于源代码树的 tools/examples/下)通过 Subversion 语言绑定接口(所以运行这个脚本须要正确的编译和安装这些程序包)连接到版本库和文件系统库。

    运行这个脚本,你可以浏览版本库中的目录,就像在 shell 下浏览文件系统一样。一开始,你 “位于” 修订版本 HEAD 的根目录中, 在命令提示符中可以看到相应的提示。 任何时候都可以使用 help 命令显示当前可用的命令帮助。

    $ svnshell.py /path/to/repos $ help Available commands: cat FILE : dump the contents of FILE cd DIR : change the current working directory to DIR exit : exit the shell ls [PATH] : list the contents of the current directory lstxns : list the transactions available for browsing setrev REV : set the current revision to browse settxn TXN : set the current transaction to browse youngest : list the youngest browsable revision number $ 浏览版本库的目录结构就像在 Unix 或 Windows shell 中一样——使用 cd 命令。任何时候,命令提示符中都会显示当前所在的修订版本(前缀为 rev:)或事务(前缀为 txn:,以及你所在的路径。你可以用 setrev 和 settxn 切换到其它修订版本或事务中去。你可以像在 Unix shell 中那样,使用 ls 命令列出目录的内容,使用 cat 命令列出文件的内容。

    例 5.1. 使用 svnshell 浏览版本库

    $ ls

    REV AUTHOR NODE-REV-ID SIZE DATE NAME

    1 sally < 2.0.1> Nov 15 11:50 A/ 2 harry < 1.0.2> 56 Nov 19 08:19 iota $ cd A $ ls

    REV AUTHOR NODE-REV-ID SIZE DATE NAME

    1 sally < 4.0.1> Nov 15 11:50 B/ 1 sally < a.0.1> Nov 15 11:50 C/ 1 sally < b.0.1> Nov 15 11:50 D/ 1 sally < 3.0.1> 23 Nov 15 11:50 mu $ cd D/G $ ls

    REV AUTHOR NODE-REV-ID SIZE DATE NAME

    1 sally < e.0.1> 23 Nov 15 11:50 pi 1 sally < f.0.1> 24 Nov 15 11:50 rho 1 sally < g.0.1> 24 Nov 15 11:50 tau $ cd ../.. $ cat iota This is the file 'iota'. Added this text in revision 2.

    $ setrev 1; cat iota This is the file 'iota'.

    $ exit $

    在上例中可以看到,可以将几条命令现在同一行中,并以分号隔开。此外,这个 shell 也能正确处理相对路径和绝对路径,以及特殊的路径.和..。

    youngest 命令将列出最年轻的修订版本。这可以用来确定 setrev 命令参数的范围—你可以浏览所有 0 到最年轻修订版本中的任何一个(它们都以整数为标识)。确定可以浏览的事务就不这么简单了。你需要使用 lstxns 命令列出哪些事务可以浏览。lstxns 命令的输出与 svnadmin lstxns 的输出相同,设置了--transaction 选项的 svnlook 命令也可以得到相同的结果。

    使用 exit 命令可以退出这个 shell。也可以使用文件结束符—Control-D(在某些 Win32 的 Python 版本中用 Control-Z 代替)。

    Berkeley DB 工具 如果你使用 Berkeley DB 版本库,那么所有纳入版本控制的文件系统结构和数据都储存在一系列数据库的表中,而这个位于版本库的 db 子目录下。这个子目录是一个标准的 Berkeley DB 环境目录,可以应用任何 Berkeley 数据库工具进行操作(参考 SleepyCat 网站 [url]http://www.sleepycat.com//url] 上关于这些工具的介绍)。[

    对于 Subversion 的日常使用来说,这些工具并没有什么用处。大多数 Subversion 版本库必须的数据库操作都集成到 svnadmin 工具中。比如,svnadmin list-unused-dblogs 和 svnadmin list-dblogs 实现了 Berkeley db_archive 命令功能的一个子集,而 svnadmin recover 则起到了 db_recover 工具的作用。

    当然,还有一些 Berkeley DB 工具有时是有用的。db_dump 将 Berkeley DB 数据库中的键值对以特定的格式写入文件中,而 db_load 则可以将这些键值对注入到数据库中。Berkeley 数据库本身不支持跨平台转移,这两个工具在这样的情况下就可以实现在平台间转移数据库的功能,而无需关心操作系统或机器架构。此外,db_stat 工具能够提供关于 Berkeley DB 环境的许多有用信息,包括详细的锁定和存储子系统的统计信息。

    版本库清理 Subversion 版本库一旦按照需要配置完成,一般情况下不需要特别的关照。不过有些时候还是需要管理员手工干预一下。svnadmin 工具就能够帮你完成以下这类工作:

    修改提交日志信息,

    移除中止的事务,

    恢复 “塞住” 的版本库,以及

    将一个版本库中的内容搬移到另一个版本库中。

    svnadmin 的子命令中最经常用到的恐怕就是 setlog。用户在提交时输入的日志信息随着相关事务提交到版本库并升级成为修订版本后,便作为新修订版本的非版本化(即没有进行版本管理)属性保存下来。换句话说,版本库只记得最新的属性值,而忽略以前的。

    有时用户输入的日志信息有错误(比如拼写错误或者内容错误)。如果配置版本库时设置了(使用 pre-revprop-change 和 post-revprop-change 钩子;参见 “钩子脚本” 一节)允许用户在提交后修改日志信息的选项,那么用户可以使用 svn 程序的 propset 命令(参见第 9 章 Subversion 完全参考)“修正” 日志信息中的错误。不过为了避免永远丢失信息,Subversion 版本库通常设置为仅能由管理员修改非版本化属性(这也是默认的选项)。

    如果管理员想要修改日志信息,那么可以使用 svnadmin setlog 命令。这个命令从指定的文件中读取信息,取代版本库中某个修订版本的日志信息(svn:log 属性)。

    $ echo "Here is the new, correct log message" > newlog.txt $ svnadmin setlog myrepos newlog.txt -r 388 即使是 svnadmin setlog 命令也受到限制。pre-和 post-revprop-change 钩子同样会被触发,因此必须进行相应的设置才能允许修改非版本化属性。不过管理员可以使用 svnadmin setlog 命令的--bypass-hooks 选项跳过钩子。

    警告 不过需要注意的是,一旦跳过钩子也就跳过了钩子所提供的所有功能,比如邮件通知(通知属性有改动)、系统备份(可以用来跟踪非版本化的属性变更)等等。换句话说,要留心你所作出的修改,以及你作出修改的方式。

    svnadmin 的另一个常见用途是查询异常的—可能是已经死亡的—Subversion 事务。通常提交操作失败时,与之相关的事务就会被清除。也就是说,事务本身及所有与该事务相关(且仅与该事务相关)的数据会从版本库中删除。不过偶尔也会出现操作失败而事务没有被清除的情况。出现这种情况可能有以下原因:客户端的用户粗暴的结束了操作,操作过程中出现网络故障,等等。不管是什么原因,死亡的事务总是有可能会出现。这类事务不会产生什么负面影响,仅仅是消耗了一点点磁盘空间。不过,严厉的管理员总是希望能够将它们清除出去。

    可以使用 svnadmin 的 lstxns 命令列出当前的异常事务名。

    $ svnadmin lstxns myrepos 19 3a1 a45 $ 将输出的结果条目作为 svnlook(设置--transaction 选项)的参数,就可以获得事务的详细信息,如事务的创建者、创建时间,事务已作出的更改类型,由这些信息可以判断出是否可以将这个事务安全的删除。如果可以安全删除,那么只需将事务名作为参数输入到 svnadmin rmtxns,就可以将事务清除掉了。其实 rmtxns 子命令可以直接以 lstxns 的输出作为输入进行清理。

    $ svnadmin rmtxns myrepos svnadmin lstxns myrepos $ 在按照上面例子中的方法清理版本库之前,你或许应该暂时关闭版本库和客户端的连接。这样在你开始清理之前,不会有正常的事务进入版本库。下面例子中的 shell 脚本可以用来迅速获得版本库中异常事务的信息:

    例 5.2. txn-info.sh(异常事务报告)

    #!/bin/sh

    Generate informational output for all outstanding transactions in

    a Subversion repository.

    REPOS="${1}" if [ "x$REPOS" = x ] ; then echo "usage: $0 REPOS_PATH" exit fi

    for TXN in svnadmin lstxns ${REPOS}; do echo "---[ Transaction ${TXN} ]-------------------------------------------" svnlook info "${REPOS}" --transaction "${TXN}" done

    可以用下面的命令使用上例中脚本: /path/to/txn-info.sh /path/to/repos。该命令的输出主要由多个 svnlook info 参见 “svnlook” 一节)的输出组成,类似于下面的例子:

    $ txn-info.sh myrepos ---[ Transaction 19 ]------------------------------------------- sally 2001-09-04 11:57:19 -0500 (Tue, 04 Sep 2001) 0 ---[ Transaction 3a1 ]------------------------------------------- harry 2001-09-10 16:50:30 -0500 (Mon, 10 Sep 2001) 39 Trying to commit over a faulty network. ---[ Transaction a45 ]------------------------------------------- sally 2001-09-12 11:09:28 -0500 (Wed, 12 Sep 2001) 0 $ 一个废弃了很长时间的事务通常是提交错误或异常中断的结果。事务的时间戳可以提供给我们一些有趣的信息,比如一个进行了 9 个月的操作居然还是活动的等等。

  • StarTeam 软件协作解决方案 at 2008年06月21日

    作为一个例子,让我们考虑 WEB 应用开发:JAVA 开发人员如何能够没有说明文档、设计人员、手册编写人员等的密切协同?

    如果不能满足下列关键需求,则这些技术协同将不能发挥作用: 非常容易使用:传统的开发工具需要大量的使用培训。而让管理人员去上课是乎有些困难。 熟悉文件管理界面:用于存取文件夹、文件和任何其它对象的界面应该与 Windows 资源管理器相似,绝大多数合作者都会使用它。 地理位置独立:管理人员和开发人员都可能分布在不同的地方,或临时变动工作地点,但他们都需要随时访问有关系统。 直接的关联导航:StarTeam 的多向链接能给技术协同者带来巨大的好处,因为链接提供了一个容易跟随、直观的导航机制,轻松访问与特定对象关联的文件、变化请求和会话等。 线索化的会话:在开发和维护过程中,StarTeam 用线索化的会话的形式保持日常的活动和决定,用户将从中积累大量有价值的知识,这些知识库可以直接被其它技术协同者访问。

     

    程序管理办公室(PMO)

    在大型项目中,经常需要一个程序办公室,是管理这个应用的中心。

    根据行业专家的研究报告,如果不使用集中的记录数据库,程序办公室将无法开展工作,集中数据库中所有受影响的对象会被跟踪。

    StarTeam 2000 是 StarTeam Professional 的一个特别版本,增加了以上功能,提供对依从跟踪系统(Compliance Tracking System)的综合支持。

    CTS 变成了建立记录数据库的理想工具,通过与 StarTeam 的集成,将数字化财富、依从工作及其在软件部件上的表示形成了一个闭环。

     

    项目管理功能

    开发环境处理文件、变化和资源,项目管理针对任务、工作分配、依赖关系和时间。

    尽管有许多项目管理产品,如 Microsoft Project,但通常都不能很好地支持开发项目,因为跟踪制作变化的时间、执行它们所用的资源和更新贯穿整个生命周期的项目信息需要很高的开销。

    这是很不幸的,因为开发人员确实希望从项目管理功能中获得好处,并且因为诸如应用软件这样关键的财富游离于项目管理框架之外。

    要提高团队生产力,必须将项目管理功能与开发环境集成在一起。集成必须能够: 支持任务,任务是一个完全激活的对象,用于关联资源、变化请求 、工作分配和变化。 完全集成任务对象与开发信息库中维护的其它对象。 支持项目模板,因此任务和工作分配能够自动应用到相似的项目中。 开发信息库和 MS Project 引擎之间透明、双向的数据更新。

    StarBase 支持上述功能,为你提供了一个完整的应用开发项目管理解决方案。

     

    协同的所有原理是-自底向上。即从低层的服务到高层次的协同功能。

    首先,协同提供的最基本的服务是产品化的、成熟的版本控制和软件配置管理。因为协同是建立在应用财富之上的,它们必须被安全地管理、审查、保护和版本化。

    StarTeam 提供的版本控制引擎支持典型的软件开发事务,如文件差异分析和合并、版本标签、建立支持和文件管理等等。

    StarTeam 的版本控制引擎与 Oracle、Symantec、Allaire、Haht Software 等其它许多软件公司提供的版本控制工具是一样的。

     

    共同访问信息技术财富

    多少年来,开发队伍已经使用版本控制保护其信息技术财富。因此,当在开发小组之间实现协同时,你将发现开发小组会逐渐抛弃传统的版本控制工具。

    StarTeam 是唯一能保护你的版本控制工具投资的这种产品,提供与其它版本控制工具(如 PVCS 和 SourceSafe)的透明互操作。不仅是导入/导出功能:完全的真实的互操作。即用户 A 可以使用 SourceSafe 建立一个文件的版本,用户 B 使用 StarTeam,那么任一用户都可以通过 SourceSafe 和 StarTeam 访问自己或他人的版本。

     

    协同框架

    在版本控制引擎互操作之上,StarTeam 建立了它最重要的功能层:协同框架。StarTeam 这一独特的体系结构,是建立世界级产品的基础。

    该功能层的技术描述是:强壮的,可伸缩的,基于标准的,面向对象的信息数据库,完全版本化的,支持多向通用化链接。用通俗的话来说就是,协同框架是 StarTeam 允许所有团队成员快速有效地进行协同工作的功能性(表示和共享关联信息)。

    协同框架提供: 从任何地方进行安全有效的访问:StarTeam 是一个客户/服务器产品,针对宽带和窄带连接进行了优化设计。用户能够使用下列方式访问 PVCS、SourceSafe 和 StarTeam 版本库: 运行在 LAN、WAN 或 TCP/IP 连接(如 Internet)上的 StarTeam 客户端应用。 运行在任何 JAVA 平台并连接在 LAN、WAN 或 Internet 上的 StarTeam JAVA 客户端。 一个标准的浏览器,不需要装入插件程序和 JAVA 小程序。

    获奖的易于使用的图形用户界面:StarTeam 已经多次被专家和用户一致评定为软件配置管理类中最容易使用的产品。无论你是开发人员或是不懂版本控制的技术协同者,都可以立即学会使用 StarTeam,并且其功能性将会给你留下深刻的影响。

    直观的文件管理界面:StarTeam 让你通过熟悉的 Windows 风格访问项目中的文件目录结构。你可以在许多文件夹中使用相同的文件名:StarTeam 使用的文件和版本名字没有限制,这与 Windows 环境不同(许多基于文件相同的工具是有限制的)。

    通用化链接引擎:StarTeam 数据库中所有的对象,无论文件、版本、变化请求或会话,都可以被任意链接,以表示它们之间逻辑和/或物理关系中包含的关联信息。你要想了解一个对象的上下文关系,只需跟着链接走。

    可视化配置管理:定义信息库的虚拟视图的能力对用户来说总是有吸引力的,但通常在高端的 SCM 工具中才会有。StarTeam 实现了这一特性并且更进一步,包括用户界面的所有可视化元素。StarTeam 用户能够可视化定义和维护虚拟视图实现隔离应用场合、阶段化(例如开发、测试、集成和产品等)、对应用过去的任何精确的日期和时间的时间游动、执行增量式调试等等。

    协同框架中的所有功能可应用于信息库中的所有对象、建立在其上的任何生产力模块以及任何与 StarTeam 通讯的应用。

     

    标准接口

    StarTeam 基于标准的集成接口层能够扩展信息数据库的功能性。它提供了从任何使用 COM 或 JAVA Beans 的应用完全存取所有信息库对象的能力。因此用 Visual Basic、JAVA 以及 COM 或 JAVA 兼容的语言编写的应用都能存取 StarTeam 中保存的版本、变化请求、会话、任务或其它任何对象。想象一下这样的可能性,将自己内部开发的应用和第三方的软件包集成在一个保存有你的信息技术财富的透明的信息库中,不管它们是在 StarTeam 还是在 SourceSafe 数据库中,这不是很美妙吗?

     

    生产力模块

    生产力模块是集成的部件,它增加了对象定义和功能性,如变化请求管理、会话、任务管理等等。

    生产力模块自动集成到 StarTeam 的用户界面。要在 StarTeam 客户端应用中实现一个新对象只要有一个动态连接库.DLL 即可。将一个.DLL 拿走,与该特殊对象(如变化请求)有关的所有功能性将立即从用户界面上消失。

    这一独特、最先进的对象集成技术是 StarTeam 强大的协同框架体系和信息数据库实现的副产品。

     

    集成自己的应用

    前面描述的基于标准的集成,同样适用于你自己内部开发的应用,可以用 VB 或任何 COM 或 JAVA Beans 兼容的语言实现。

     

    集成多厂家的应用

    互操作层让版本控制引擎协同工作,协同框架使用户合作。同样,标准接口层实现技术的协同。

    StarTeam 正在推出 StarPartner 软件合作伙伴策略,通过 StarTeam SDK,保证其它技术能够利用 StarTeam 生产力模块同样的机制使用产品信息数据库的服务。

     

    StarTeam 是目前唯一的企业级协同解决方案。

    StarTeam 是一个集成的解决方案,为企业信息组织中从开发人员到项目管理人员的所有成员带来了好处。

    这一革命性的解决方案事实上正在成为标准。许多全球性的大型企业正在采用 StarTeam,通过建立跨团队、跨部门、跨专业的协同工作,提高应用队伍的效率

  • 虽然公司现在不是用的 svn,但是我还是在公司的测试机上安装了一个 svn 管理我的文档。方便多了。

    其实在软件研发来看,文档管理也是 SCM 工作内容的一部分。

  • 公司不错,一个咨询的公司,号称,只要能力有,工资不用谈。

    从这个职位可以看出,这个要求不仅仅是一个软件配置管理工程师啊,还应该加上一个 CIO 的头衔,一个咨询师的头衔。

  • Jazz 平台技术概览 at 2008年06月20日
    • Team Central 视图

    Team Central 视图是可由用户自定义的 Jazz 平台协作中心,允许团队成员查看团队中正在发生的事情(图 5)。Team Central 是带有多个通过扩展点提供的部分的 Eclipse 视图。典型的部分显示简明的摘要,并连接到另一个提供更详细信息的视图或编辑器。用户可以在任何时候配置哪些部分可见。Jazz 提供了一个用于编写各个部分的简单框架,并提供了用于产生简明的可视化摘要的特殊图表小部件。Jazz 内核提供了相关的部分,用于显示通常有用的东西,例如 Web Feed 和聊天好友列表。其他 Jazz 组件提供了组件特定的部分,例如用于工作项和构建版本的部分。

    图 5:Team Central 视图 [local] 4[/local]

    * Team Artifacts 视图

    Team Artifacts 视图提供了对与 Jazz 相关的构件的集中访问(图 6)。该视图以按项目区域分组并按团队区域筛选的方式显示构件。各个条目通过扩展点提供。Jazz 内核提供了用于诸如 Web Feed 订阅等的条目。其他 Jazz 组件提供了组件特定的构件,例如构建版本和计划。

    图 6:Team Artifacts 视图 [local] 3[/local]

    Web UI

    除了高质量地将 Jazz 集成到 Eclipse 和其他 IDE 中以外,Jazz 还允许用户从 Web 浏览器直接访问 Jazz 服务器。该 UI 称为 Jazz Web UI。Jazz Web UI 比 IDE 更适合于随意或偶然的用户,因为它不需要在客户端计算机上安装任何特殊软件;所需要的只是一个 Web 浏览器。

    每个 Jazz 服务器具有一个主网页,用户可以在其中选择项目区域并登录。一旦已登录,用户即可与 Jazz 服务器交互,并浏览 Jazz 存储库中的信息,包括阅读最近的事件、输入和更新工作项和下载构建版本。图 7 演示了显示某个工作项的 Jazz Web UI。

    图 7:显示工作项的 Jazz Web UI 显示工作项的 Jazz Web UI [local] 6[/local] * Jazz Web UI 是模块化的

    Jazz 平台提供了可扩展的体系结构和 API,可以简化特定组件的基于 Web 的丰富 UI 的开发。与 Jazz 组件的其他部分一样,组件的 Web UI 被开发为在 Jazz 服务器上运行的 Eclipse 插件。每个 Web UI 插件向某个扩展点提供组件特定的网页和脚本。在运行时,服务器将所有已安装的组件提供的内容聚合到构成服务器 Web UI 的网页中。

    Jazz 平台的技术预览版的 Web UI 包括几个关键的 Jazz 组件,包括工作项、构建版本和报告。

    * Jazz Web UI 使用 Ajax 和 REST

    Jazz Web UI 遵循一个基于 Ajax 和 REST 的编程模型。Ajax 是一种使用基于标准的 Web 技术(HTML、JavaScript、CSS 和 DOM)的 Web 编程风格,这些技术无需刷新整个页面即可实现页面和服务器之间的交互。传输到客户端的 Web UI 包含脚本,这些脚本处于 Web 浏览器中显示的 GUI 元素和带有逻辑以及存储库的服务器之间。客户端脚本语言为 JavaScript。服务器请求采用 URL 形式,这些 URL 调用 REST 样式的 Web 服务;响应为 XML 或 JSON 形式。使用此方法,所有用户界面逻辑和 UI 状态完全驻留在客户端上的 Web 浏览器中,并且所有逻辑和执行状态都保留在服务器上。与传统网站相比,这种方法使得用户界面可以更灵敏地响应用户操作。这种方法还提供了很好的可伸缩性:服务是无状态的,会话数据不通过网络来回发送,并且客户端缓存可以优化存储库中不常更改的项的获取。

    构建 Jazz 组件的 Web UI 涉及到:

    * 使用 HTML、JavaScript、CSS 和 DOM 的组合来编写 Ajax 样式的客户端 GUI * 将服务器端业务逻辑编写为采用 Java 实现的 REST 样式的 Web 服务

    Jazz 平台的 Web UI Foundation 部分同时在两端提供了有用的框架。对于客户端 GUI,Jazz 基于开放源代码的 Dojo Toolkit,后者通过提供一个抽象浏览器之间的不一致性的丰富小部件和事件框架,从而简化了 Ajax 开发。对于 REST 服务,Jazz 提供一个 REST 框架,此框架抽象了处理 REST 请求的细节(HTTP、数据封送和取消分送等等)。REST 服务通过 Java 接口进行定义。该 Java 接口和项的基于 EMF 的存储模型在运行时用于对请求和响应进行封送处理。在许多情况下,REST 服务方法的实现只是调用组件的主服务接口上的对应方法。

    与其他生命周期工具的互操作

    Jazz 旨在涵盖全范围的软件生命周期工具,并在 Jazz 存储库中存储所有的持久数据,数据在存储库中进行集中管理。尽管 Jazz 有此雄心,也可能存在让 Jazz 客户继续使用其他软件生命周期工具和系统的理由,这些工具和系统在自己的存储库中存储持久数据。也许组织对某个特定工具所提供的服务非常满意,而未看见切换到使用基于 Jazz 的等效工具的重大好处;也许组织正在逐渐地过渡到 Jazz,并将在几年时间内分阶段推进。无论是什么原因,都存在让 Jazz 与企业中正在使用的其他软件生命周期工具和系统互操作的持续需要。

    Jazz 和外部生命周期工具在 GUI 级别与相同桌面环境(例如 Eclipse IDE 或 Web 浏览器)的集成,使得用户同时访问两种工具变得非常方便。在某些情况下,这可能就足够了。由于外部生命周期工具的所有持久数据存储在 Jazz 存储库之外,互操作程度可能非常有限,使其无法参与 Jazz 特定的操作。

    Jazz 提供了一个用于代理项的轻量级框架。代理项一对一地对应于另一个系统中的相关对象。代理项是通用的;它们通过标识字符串(例如某个 URI)引用外部对象,并且能够携带任意的键 - 值属性集,这些属性用于表示外部对象状态的 “相关” 部分。如果外部对象的类型在 Jazz 中具有直接的对等项类型,则可以将外部对象与对应的 Jazz 对等项进行配对。在此情况下,代理项提供两者之间的连接。每个代理项引用一个同步规则,该规则指定外部项中的命名属性与 Jazz 对等项的命名属性之间的映射。映射是有方向的:传入映射确定对外部对象的更改如何转换为对 Jazz 对等项的更改,而传出映射则确定对 Jazz 对等项的更改如何转换为对外部对象的更改。同步规则还确定做实际工作的服务器端同步管理器。可以通过扩展点提供新的同步管理器类型。

    参考资料 学习

    * 本文中文版由 Jazz.net 授权发布。您可以通过免费注册成为 Jazz.net 的用户,查看本文的 英文原文。

    * 本文中所涉及的 Jazz 使用的许可证、协议和版权声明,包含在本文的英文原文中。请注册成为免费注册的 Jazz.net 用户,查看此 Jazz 使用的许可证、协议和版权声明。

    * 各个可选组件的概述文档包含在本文的英文原文中。感兴趣的读者可以参阅英文原文对各个可选组件的概述文档,以了解进一步的信息: o 工作物件(Work Item)——为管理缺陷报告、功能请求和其他开发任务提供支持——有关详细信息请参阅 Jazz Work Item Overview o 源代码控制(Source Control)——管理源代码和其他数字化资产——有关详细信息请请参阅 Jazz Source Control Overview o Team Build——提供构建集成——有关详细信息请参阅 Jazz Build Overview o 需求(Requirements)——提供需求的创建和管理——有关详细信息请参阅 Jazz Requirements Overview o 团队报告(Team Reports)——提供诸如项目状况等报告——有关详细信息请参阅 Jazz Reports Overview o 敏捷规划(Agile Planning)——提供轻量级规划——有关详细信息请参阅 Jazz Agile Planning Overview

    转载自: [url]http://www.ibm.com/developerworks/cn/rational/jazz/r-jazz-platform-overview/index.html?ca=drs-cn-0429&amp/url];ca=dkw-Jazz[

  • Jazz 平台技术概览 at 2008年06月20日

    除了按项 ID 直接检索某个项以外,服务器端 API 还包括基于项的属性和关系对存储库中的项运行复杂查询的操作。该查询语言基于面向对象的 EJB QL 的语法,此语法经过了改编以适应存储库中找到的对象类型。

    存储库读和写操作是原子的。服务器端 API 还包括一个操作,用于显式地将任意的读和写操作序列包装为单个原子事务。Jazz 具有对来往于存储库的内容对象进行流处理的服务器端 API,旨在使流处理能够在存储库事务之外安全地完成。

    * Feed 服务

    Jazz 还提供了一个由存储库支持的 Feed 服务。组件通过服务器端 API 报告更改事件,以通告相关的更改,例如某个构建版本的完成,或者到某个流的传输。更改事件记录在存储库中(并参与常规的存储库事务)。Feed 服务发布最近的更改事件的 Web Feed(Atom 或 RSS),该 Web Feed 适合于由任何与标准兼容的 Feed 阅读器(分别为 Atom 1.0 或 RSS 2.0)进行分析。尽管所有的更改事件具有相同的固定结构,但是组件可以通过服务器端扩展点注册专门的呈现器 (renderer),该呈现器选择性地覆盖从更改事件到 Feed 条目的缺省转换,并允许组件添加自定义文本元素和链接。

    * 关系数据库后端

    存储库由一个关系数据库提供后端支持。Jazz 的技术预览版支持两种关系数据库系统:Apache Derby 和 IBM DB2®。Apache Derby 是一个最适合于小型存储库的开放源代码关系数据库系统。IBM DB2 是一个为各种规模的存储库提供解决方案的商用产品。逻辑模型、存储模型和服务器端 Jazz API 的语义全都与特定的关系数据库系统选择无关。将来的版本中可能添加对其他关系数据库系统的支持。

    在运行时,Jazz 服务器发现由组件通过扩展点提供的存储模型。Repository 组件将存储模型映射到关系数据库模式和表。根据该映射,用于获取、保存、删除和查询项的服务器端 API 操作在运行时被转换为 SQL 语句,并由关系数据库系统执行。

    该事务机制利用了保存操作的 “如果被并发修改则失败”(fail-if-concurrently-modified) 语义以提供完整性。在读写事务期间保存的项保留在内存中,直到该事务结束,并延迟实际的数据库更新(尽管 Jazz 确保在事务期间检索项时可以看到该更新)。只有在事务提交时才需要数据库写入锁,以确保原子地更新已修改的项,而不受到并发更新的干扰。

    * 客户端

    在客户端,组件的客户端库为客户端提供了 API,以便客户端操作组件选择公开的项类型。创建、更新和删除存储库中的项只能通过上面讨论的服务器端机制来完成。组件的客户端库调用组件的服务方法,这些方法在服务器上远程运行并访问存储库。在客户端和服务器之间传递的参数和结果类型可以包括在组件的存储模型中声明的类型。存储模型的运行时表示形式用于对对象进行封送处理。组件的存储模型包含在组件的公共插件中,该插件同时安装在客户端和服务器上。建立客户端和服务器之间的连接以后,Jazz 将检查两端是否具有相同版本的存储模型。

    Jazz 客户端接口需要对客户端片段可用,例如 Eclipse IDE 中的各种视图和编辑器。这意味着该接口必须提供相关方法,以帮助客户端的各个部分在所访问的存储库中的项的当前状态方面保持协调。Repository 为此目的而提供了一个客户端项管理器。对于简单和可审核的项类型,项管理器分配共享项。共享项是存在于客户端的内存中对象,并且可由需要对该特定项的当前状态进行读访问的客户端使用。客户端不允许修改共享项;对于客户端来说,共享项是只读对象。当客户端将该项的新状态保存到存储库时,各个属性的新值将复制到共享项中,并向相关各方发送通知事件。由于共享项实例就是在该项发生改变的相同地方进行修改的,因此存储对该实例的引用的客户端随时可以访问该项的当前状态,而不需要进行服务器往返以检索该项(除非是在最初向项管理器请求某个特定共享项的时候)。

    与服务器端编程模型相反,不存在用于构成针对存储库的原子事务的客户端机制。一般情况下,在设计组件的客户端接口中的方法时必须考虑到潜在的并发更新,并将其实现为在服务器上作为原子事务运行的组件特定的服务方法。Repository 组件具有用于针对存储库上载和下载内容对象的客户端 API,旨在使流处理能够在存储库事务之外安全地完成。

    Team Process 组件

    Team Process 组件提供了 Jazz 的流程支持基础。Team Process 是一个内核组件,因此其功能对所有客户端和服务器配置中的其他组件可用。

    * 流程

    在此上下文中,流程是指用于对工作进行组织的实践、规则、指导原则和约定的集合。团队的流程是团队已决定(或养成)的行事方式的总和。

    对于非常小的团队,流程通常是非正式的,并且没有文档记录。随着团队的发展壮大,流程的部分内容可能在团队的项目主页上做了文档记录,以使新的团队成员能够迅速吸收这些内容。大型组织可能编写了预期其项目团队要遵守的一般实践和过程的描述;项目团队预期将以标准流程模板为起点,并对标准流程模板进行自定义以适合项目和团队。有些组织和团队则更进一步,并创建了涵盖流程的绝大部分的正式模型。

    * Jazz 是一个有流程意识的平台

    Jazz 旨在实现跨整个软件开发生命周期的全面支持。贯穿所有项目阶段的一条主线是团队成员一致同意遵循的流程。通过教会 Jazz 有关流程的知识,Jazz 就能够以流程特定的方式帮助团队。这种流程支持可以具有广泛(并且完全开放)的形式,范围从动态规则检查,到提供在线(例如,F1 键)流程帮助,再到自动化簿记工作。

    Jazz 通过以下方式支持流程:

    * Jazz 平台具有流程意识。一般情况下,团队的流程可以影响某个团队成员所做工作的任何方面。流程的概念植根于 Jazz 平台中。团队的流程以显式的方式表示,团队成员在系统中做的所有工作都在团队流程的上下文中发生。 * Jazz 组件是支持流程的。包括初始核心在内的所有 Jazz 组件都设计为允许主要流程对组件的操作和项施加影响。 * Jazz 平台使用标准 Jazz 项来表示流程,这些项存储在存储库中。这种流程表示形式可以描述所有类型的流程,并且可以捕获和制定与实际一样多(或一样少)的团队流程。 * Jazz 平台独立于流程。Jazz 本身没有用于强制要在任何特定情况下做什么的内置流程。团队将负责定义适当的控制流程来为他们的项目做出这样的决策。技术预览版包括了代表性的流程模板,其中包括封装 Jazz 项目团队本身使用的流程的一个早期版本的模板。

    以下几个部分将详述以上内容。

    * 流程支持基础

    项目区域是系统对软件项目的表示形式,并且旨在完整地承载开发和维护方面。项目区域在存储库中存储为顶级项。项目区域拥有构成项目资源的所有项目构件和这些构件之间的所有关系。对项目区域和其中的构件的访问通过权限进行控制。

    存在一个从事该项目的人员团队。人员由贡献者 (contributor) 项显式地表示。团队显式地表示为属于该项目区域的项目构件。贡献者组成的团队一般负责该项目区域和其中的一切。

    与某个项目区域关联的是一个团队流程。团队流程控制在关联的项目区域中从事的所有活动、构件、构件关系和操作。流程由一个流程规范和一个迭代结构进行定义。流程规范和迭代结构都存储在项目区域中。迭代结构定义现有的开发线 (development line),并将开发线分解为各个迭代。它还定义了每条开发线的当前迭代是哪一个迭代。流程规范描述团队成员所能扮演的角色,以及在多个迭代中适用于每个角色的流程规则。流程规范还定义了哪些流程规则可以进行进一步的自定义。

    项目区域划分为各个团队区域,并安排为具有多个根的层次结构。每个团队区域确切地仅属于一条开发线。每个团队区域可以自定义沿着父链继承的流程规则。因此,团队区域的流程规则可能与项目区域以及项目区域的流程规范设定的范围中的其他团队区域的流程规则不同。

    项目区域的每个项目构件确切地仅属于其中一个团队区域。随着时间的推移,项目构件可能从一个团队区域移动到另一个团队区域,但是始终在最初的项目区域的范围之内。项目构件与项目区域和项目区域与其控制流程之间的关联相结合,允许系统的各个部分从项目构件导航到控制该构件操作的特定流程的表示形式。这使得系统的各个部分可以按照对团队成员有帮助并且与流程保持一致的方式操作。

    * Jazz 组件是支持流程的

    支持流程的 Jazz 组件的设计特点在于,在系统已知的某个流程控制着所做工作的环境中,这样的组件能够表现良好。流程支持必须开放某个组件,以便流程规则能够指导该组件。 “支持流程” 对每个组件的含义千差万别,但是所有 Jazz 组件预期都以适合于其功能的方式支持流程。其目标是使可能对制定任何类型的流程有用的东西变得可用。

    组件本身保持独立于流程:它没有规定自己提供的哪些功能应该在任何特定的情况下使用。控制流程将通过指定流程规则集来负责做出这样的决策。但是,要开放什么以及开放程度如何,则完全由组件编写人员决定。

    组件提供流程支持的几种一般方法如下:

    * 组件配置数据。 组件可以声明自己具有影响其行为的内部配置参数。在任何时候,组件都可以要求控制流程提供任何配置参数的当前值。组件必须处理控制流程没有做出任何规定的情况。 * 操作参与。组件一般提供了用于操作自己的构件类型的操作。在调用某个操作时,组件可以为控制流程提供在操作前和操作后插入适当逻辑的机会。例如,Source Control 组件允许在将代码更改传输到流之前执行任意检查。在任何特定情况下执行的检查由控制流程规定,并且可以是所传输到的流的某个功能、所传输的代码更改或开发周期的阶段。 * 事件报告。组件一般会报告事件,这些事件反映了在执行某个操作的过程中所做的更改。这些事件为控制流程提供了监视更改并在已做出更改之后采取适当操作的能力。

    每个组件编写人员将负责确定这些类型的流程规则中哪些对他们的组件有意义。

    组件的客户端库插件通过扩展点以声明的方式定义其对流程支持的贡献。类似地,组件的服务实现插件定义了服务器端对流程支持的贡献。

    客户端和服务器端流程实施各有其用途。客户端流程实施可以通过 UI 与用户交互,并与 IDE 交互;服务器端流程实施则不能与其中任一方交互。另一方面,服务器端流程实施可以在与主操作相同的存储库事务中运行;客户端流程实施则不是事务性的。例如,这使得服务器端流程代码可以将更改集传输到流,并向所传输的更改集的工作项添加说明,这一切工作全都在同一个原子事务中完成。服务器端流程支持不能规避,而客户端流程支持天生就不太可靠,因为它依赖于各个开发人员个人的客户端配置。

    * 流程规范

    正如计算机程序是对事情应该如何在运行时动态地展开的静态描述一样,流程规范是对事情应该如何在软件开发过程期间展开的静态描述。在后一种情况下,动态展开的是团队成员执行的工作;项目区域是动态上下文;项目构件是运行时对象。

    当从事该项目的团队成员着手做他们的工作时,他们将遇到受流程规则影响的情形。理想的情况下,系统在发生这种情形时发出通知,并将以有帮助并且与流程保持一致的方式进行干预。问题的要点在于如何将这种理想情况投入实际应用。仅当团队成员执行某个触发组件特定的流程实施机制时,流程支持才会发挥作用。使用受影响的构件,操作将确定自己应该在哪一个团队区域的上下文中执行。流程支持通过参考沿团队区域的父链的流程自定义和项目区域中适用于当前迭代的流程规范,从而确定团队区域的有效流程。有效流程提供了操作的参与者列表、组件配置数据等等。

    流程规范以声明的形式表示,而基本操作则表示为 Java 代码。流程规范以能够高效地执行的编译形式保存。在特定情形下执行流程规范意味着确定和执行适用的流程规则。

    存储在项目区域中的流程规范是在流程模板基础上实例化而来的。Jazz 提供了用于创作流程模板、编辑项目区域的流程规范和迭代结构以及编辑团队区域的流程自定义的方法。

    使用工具(例如 Eclipse Process Framework 所提供的工具)创作的流程描述可部署到 Jazz 存储库,并与现有的流程模板相关联。然后对于其流程规范派生自这些流程模板的项目区域,可以在其上下文中查看流程描述。

    可选的平台组件

    除了提供通用基础设施的内核组件以外,还有其他平台组件处理软件开发生命周期的特定方面。与内核组件相反,其他组件是可选的。感兴趣的读者可以参阅各个组件的概述文档以了解进一步的信息:

    * 工作物件(Work Item)——为管理缺陷报告、功能请求和其他开发任务提供支持。(有关详细信息请参阅 参考资料) * 源代码控制(Source Control)——管理源代码和其他数字化资产。(有关详细信息请参阅 参考资料) * 团队构建(Team Build)——提供构建集成。(有关详细信息请参阅 参考资料) * 需求(Requirements)——提供需求的创建和管理。(有关详细信息请参阅 参考资料) * 团队报告(Team Reports)——提供诸如项目状况等报告。(有关详细信息请参阅 参考资料) * 敏捷规划(Agile Planning)——提供轻量级规划。(有关详细信息请参阅 参考资料)

    客户端 GUI

    用户将通过桌面上的 UI 与 Jazz 交互。本部分研究主要的 UI:基于 Eclipse 的 IDE 和 Web 浏览器。

    IDE 集成

    * 将 Jazz 集成到 Eclipse 中

    Eclipse 平台 是一个用于工具集成的通用平台。设计用于集成应用程序开发生命周期工具子分类的 Jazz 平台旨在与包括 Eclipse 在内的其他集成工具密切协作。实际上,Eclipse 是主要的客户端 IDE 集成工具。

    在 UI 级别,Jazz 平台为 Eclipse 贡献了两个高端视图部分:Team Central 和 Team Artifacts。这两个视图充当信息中心,并且旨在由 Jazz 组件进行扩展。

  • Jazz 技术文档中心 at 2008年06月20日
  • Jazz 新手入门 at 2008年06月20日

    scmroad 于 2008-6-20 16:26 发表
    Jazz 是什么?

    下一代协作平台

    Jazz 是 IBM Rational 面向软件交付技术的下一代协作平台。Jazz 平台经过精心设计,专门面向全球化和跨地域团队开发,将改变人们协作构建软件的方式——提高软件交付的协作性、效率和透明 ... [/quote] Jazz 支持各种类型的客户端.png

  • Win2000 下 Bugzilla 安装实录 at 2008年06月19日

    我自己的经验:

    最好不要在 win2000,windows XP 下装 bugzilla 如果可以的话,最好在 windows 2003 server 下安装。

  • Win2000 下 Bugzilla 安装实录 at 2008年06月19日

    9 附录:(PerlModule.bat) @echo off

    @echo ****Start install perl module for Bugzilla******** @echo ***************Ready Go!!!********************

    @echo ********* Install Bundle::Bugzilla Module ************ call ppm install Bundle::Bugzilla @echo OK!!

    @echo ********* Install Chart Module ************ call ppm install Chart @echo OK!!

    @echo ********* Install CGI Module ************ call ppm install CGI @echo ********* Failed??:) @echo ********* Download it from fllowing URL ********** @echo [url]http://cpan.shellhung.org/authors/id/L/LD/LDS/CGI.pm-3.04.tar.gz/url][ @echo ********* Use it with fllowing step ********** @echo ********* 1. Upzip this tar.gz @echo ********* 2. Run the CMD.exe @echo ********* 3. Into the upzipped tar.gz use dos command "cd" @echo ********* 4. perl MakeFile.pl @echo ********* 5. nmake @echo ********* 6. nmake test @echo ********* 7. nmake install @echo ********* 8. OK!!

    @echo ********* Install Date::Format Module ************ call ppm install Date::Format @echo ********* Failed??:) @echo ********* Download it from fllowing URL ********** @echo [url]http://cpan.shellhung.org/authors/id/G/GB/GBARR/TimeDate-1.16.tar.gz/url][ @echo ********* Use it with fllowing step ********** @echo ********* 1. Upzip this tar.gz @echo ********* 2. Run the CMD.exe @echo ********* 3. Into the upzipped tar.gz use dos command "cd" @echo ********* 4. perl MakeFile.pl @echo ********* 5. nmake @echo ********* 6. nmake test @echo ********* 7. nmake install @echo ********* 8. OK!!

    @echo ********* Install AppConfig Module ********** call ppm install AppConfig @echo ********* Failed??:) @echo ********* Download it from fllowing URL ********** @echo [url]http://cpan.shellhung.org/authors/id/A/AB/ABW/AppConfig-1.55.tar.gz/url][ @echo ********* Use it with fllowing step ********** @echo ********* 1. Upzip this tar.gz @echo ********* 2. Run the CMD.exe @echo ********* 3. Into the upzipped tar.gz use dos command "cd" @echo ********* 4. perl MakeFile.pl @echo ********* 5. nmake @echo ********* 6. nmake test @echo ********* 7. nmake install @echo ********* 8. OK!!

    @echo ********* Install Template::Toolkit Module ********** call ppm install Template::Toolkit @echo ********* Failed??:) @echo ********* Download it from fllowing URL ********** @echo [url]http://cpan.shellhung.org/authors/id/A/AB/ABW/Template-Toolkit-2.12.tar.gz/url][ @echo ********* Use it with fllowing step ********** @echo ********* 1. Upzip this tar.gz @echo ********* 2. Run the CMD.exe @echo ********* 3. Into the upzipped tar.gz use dos command "cd" @echo ********* 4. perl MakeFile.pl @echo ********* 5. nmake @echo ********* 6. nmake test @echo ********* 7. nmake install @echo ********* 8. OK!!

    @echo ********* Install Data::Dumper Module ********** call ppm install Data::Dumper @echo OK!!

    @echo ********* Install Date::Format Module ********** call ppm install Date::Format @echo OK!!

    @echo ********* Install DBI Module ********** call ppm install DBI @echo OK!!

    @echo ********* Install DBD::mysql Module ********** call ppm install DBD::mysql @echo OK!!

    @echo ********* Install File::Spec Module ********** call ppm install File::Spec @echo OK!!

    @echo ********* Install File::Temp Module ********** call ppm install File::Temp @echo OK!!

    @echo ********* Install Text::Wrap Module ********** call ppm install Text::Wrap @echo OK!!

    @echo ********* Install GD Module ********** call ppm install GD @echo OK!!

    @echo ********* Install GD::Graph Module ********** call ppm install GD::Graph @echo OK!!

    @echo ********* Install GD::Text::Align Module ********** call ppm install GD::Text::Align @echo OK!!

    @echo ********* Install PatchReader Module ********** call ppm install PatchReader @echo OK!!

    @echo ********* Install MIME::Tools Module ********** call ppm install MIME::Tools @echo OK!!

    @echo ********* Install MIME::Base64 Module ********** call ppm install MIME::Base64 @echo OK!!

    @echo ********* Install Authen::SASL Module ********** call ppm install Authen::SASL @echo OK!!

    pause

    (全文完)

    作者 Blog:[url]http://blog.csdn.net/ycw//url][

  • Continuous Integration at 2008年06月19日

    One of the most difficult parts of software development is making sure that you build the right software. We've found that it's very hard to specify what you want in advance and be correct; people find it much easier to see something that's not quite right and say how it needs to be changed. Agile development processes explicitly expect and take advantage of this part of human behavior.

    To help make this work, anyone involved with a software project should be able to get the latest executable and be able to run it: for demonstrations, exploratory testing, or just to see what changed this week.

    Doing this is pretty straightforward: make sure there's a well known place where people can find the latest executable. It may be useful to put several executables in such a store. For the very latest you should put the latest executable to pass the commit tests - such an executable should be pretty stable providing the commit suite is reasonably strong.

    If you are following a process with well defined iterations, it's usually wise to also put the end of iteration builds there too. Demonstrations, in particular, need software whose features are familiar, so then it's usually worth sacrificing the very latest for something that the demonstrator knows how to operate. Everyone can see what's happening

    Continuous Integration is all about communication, so you want to ensure that everyone can easily see the state of the system and the changes that have been made to it.

    One of the most important things to communicate is the state of the mainline build. If you're using CruiseControl there's a built in web site that will show you if there's a build in progress and what was the state of the last mainline build. Many teams like to make this even more apparent by hooking up a continuous display to the build system - lights that glow green when the build works, or red if it fails are popular. A particularly common touch is red and green lava lamps - not just do these indicate the state of the build, but also how long it's been in that state. Bubbles on a red lamp indicate the build's been broken for too long. Each team makes its own choices on these build sensors - it's good to be playful with your choice (recently I saw someone experimenting with a dancing rabbit.)

    If you're using a manual CI process, this visibility is still essential. The monitor of the physical build machine can show the status of the mainline build. Often you have a build token to put on the desk of whoever's currently doing the build (again something silly like a rubber chicken is a good choice). Often people like to make a simple noise on good builds, like ringing a bell.

    CI servers' web pages can carry more information than this, of course. CruiseControl provides an indication not just of who is building, but what changes they made. Cruise also provides a history of changes, allowing team members to get a good sense of recent activity on the project. I know team leads who like to use this to get a sense of what people have been doing and keep a sense of the changes to the system.

    Another advantage of using a web site is that those that are not co-located can get a sense of the project's status. In general I prefer to have everyone actively working on a project sitting together, but often there are peripheral people who like to keep an eye on things. It's also useful for groups to aggregate together build information from multiple projects - providing a simple and automated status of different projects.

    Good information displays are not only those on a computer screens. One of my favorite displays was for a project that was getting into CI. It had a long history of being unable to make stable builds. We put a calendar on the wall that showed a full year with a small square for each day. Every day the QA group would put a green sticker on the day if they had received one stable build that passed the commit tests, otherwise a red square. Over time the calendar revealed the state of the build process showing a steady improvement until green squares were so common that the calendar disappeared - its purpose fulfilled. Automate Deployment

    To do Continuous Integration you need multiple environments, one to run commit tests, one or more to run secondary tests. Since you are moving executables between these environments multiple times a day, you'll want to do this automatically. So it's important to have scripts that will allow you to deploy the application into any environment easily.

    A natural consequence of this is that you should also have scripts that allow you to deploy into production with similar ease. You may not be deploying into production every day (although I've run into projects that do), but automatic deployment helps both speed up the process and reduce errors. It's also a cheap option since it just uses the same capabilities that you use to deploy into test environments.

    If you deploy into production one extra automated capability you should consider is automated rollback. Bad things do happen from time to time, and if smelly brown substances hit rotating metal, it's good to be able to quickly go back to the last known good state. Being able to automatically revert also reduces a lot of the tension of deployment, encouraging people to deploy more frequently and thus get new features out to users quickly. (The Ruby on Rails community developed a tool called Capistrano that is a good example of a tool that does this sort of thing.)

    In clustered environments I've seen rolling deployments where the new software is deployed to one node at a time, gradually replacing the application over the course of a few hours.

    See Related Article: Evolutionary Database Design

    A common roadblock for many people doing frequent releases is database migration. Database changes are awkward because you can't just change database schemas, you also have to ensure data is correctly migrated. This article describes techniques used by my colleague Pramod Sadalage to do automated refactoring and migration of databases. The article is an early attempt the capture the information that's described in more detail by Pramod and Scott Amblers book on refactoring databases[ambler-sadalage].

    A particularly interesting variation of this that I've come across with public web application is the idea of deploying a trial build to a subset of users. The team then sees how the trial build is used before deciding whether to deploy it to the full user population. This allows you to test out new features and user-interfaces before committing to a final choice. Automated deployment, tied into good CI discipline, is essential to making this work. Benefits of Continuous Integration

    On the whole I think the greatest and most wide ranging benefit of Continuous Integration is reduced risk. My mind still floats back to that early software project I mentioned in my first paragraph. There they were at the end (they hoped) of a long project, yet with no real idea of how long it would be before they were done.

    The trouble with deferred integration is that it's very hard to predict how long it will take to do, and worse it's very hard to see how far you are through the process. The result is that you are putting yourself into a complete blind spot right at one of tensest parts of a project - even if you're one of the rare cases where you aren't already late.

    Continuous Integration completely finesses this problem. There's no long integration, you completely eliminate the blind spot. At all times you know where you are, what works, what doesn't, the outstanding bugs you have in your system.

    Bugs - these are the nasty things that destroy confidence and mess up schedules and reputations. Bugs in deployed software make users angry with you. Bugs in work in progress get in your way, making it harder to get the rest of the software working correctly.

    Continuous Integrations doesn't get rid of bugs, but it does make them dramatically easier to find and remove. In this respect it's rather like self-testing code. If you introduce a bug and detect it quickly it's far easier to get rid of. Since you've only changed a small bit of the system, you don't have far to look. Since that bit of the system is the bit you just worked with, it's fresh in your memory - again making it easier to find the bug. You can also use diff debugging - comparing the current version of the system to an earlier one that didn't have the bug.

    Bugs are also cumulative. The more bugs you have, the harder it is to remove each one. This is partly because you get bug interactions, where failures show as the result of multiple faults - making each fault harder to find. It's also psychological - people have less energy to find and get rid of bugs when there are many of them - a phenomenon that the Pragmatic Programmers call the Broken Windows syndrome.

    As a result projects with Continuous Integration tend to have dramatically less bugs, both in production and in process. However I should stress that the degree of this benefit is directly tied to how good your test suite is. You should find that it's not too difficult to build a test suite that makes a noticeable difference. Usually, however, it takes a while before a team really gets to the low level of bugs that they have the potential to reach. Getting there means constantly working on and improving your tests.

    If you have continuous integration, it removes one of the biggest barriers to frequent deployment. Frequent deployment is valuable because it allows your users to get new features more rapidly, to give more rapid feedback on those features, and generally become more collaborative in the development cycle. This helps break down the barriers between customers and development - barriers which I believe are the biggest barriers to successful software development. Introducing Continuous Integration

    So you fancy trying out Continuous Integration - where do you start? The full set of practices I outlined above give you the full benefits - but you don't need to start with all of them.

    There's no fixed recipe here - much depends on the nature of your setup and team. But here are a few things that we've learned to get things going.

    One of the first steps is to get the build automated. Get everything you need into source control get it so that you can build the whole system with a single command. For many projects this is not a minor undertaking - yet it's essential for any of the other things to work. Initially you may only do build occasionally on demand, or just do an automated nightly build. While these aren't continuous integration an automated nightly build is a fine step on the way.

    Introduce some automated testing into you build. Try to identify the major areas where things go wrong and get automated tests to expose those failures. Particularly on an existing project it's hard to get a really good suite of tests going rapidly - it takes time to build tests up. You have to start somewhere though - all those cliches about Rome's build schedule apply.

    Try to speed up the commit build. Continuous Integration on a build of a few hours is better than nothing, but getting down to that magic ten minute number is much better. This usually requires some pretty serious surgery on your code base to do as you break dependencies on slow parts of the system.

    If you are starting a new project, begin with Continuous Integration from the beginning. Keep an eye on build times and take action as soon as you start going slower than the ten minute rule. By acting quickly you'll make the necessary restructurings before the code base gets so big that it becomes a major pain.

    Above all get some help. Find someone who has done Continuous Integration before to help you. Like any new technique it's hard to introduce it when you don't know what the final result looks like. It may cost money to get a mentor, but you'll also pay in lost time and productivity if you don't do it. (Disclaimer / Advert - yes we at ThoughtWorks do some consultancy in this area. After all we've made most of the mistakes that there are to make.) Final Thoughts

    In the years since Matt and I wrote the original paper on this site, Continuous Integration has become a mainstream technique for software development. Hardly any ThoughtWorks projects goes without it - and we see others using CI all over the world. I've hardly ever heard negative things about the approach - unlike some of the more controversial Extreme Programming practices.

    If you're not using Continuous Integration I strongly urge you give it a try. If you are, maybe there are some ideas in this article that can help you do it more effectively. We've learned a lot about Continuous Integration in the last few years, I hope there's still more to learn and improve. Acknowledgments

    First and foremost to Kent Beck and my many colleagues on the Chrysler Comprehensive Compensation (C3) project. This was my first chance to see Continuous Integration in action with a meaningful amount of unit tests. It showed me what was possible and gave me an inspiration that led me for many years.

    Thanks to Matt Foemmel, Dave Rice, and everyone else who built and maintained Continuous Integration on Atlas. That project was a sign of CI on a larger scale and showed the benefits it made to an existing project.

    Paul Julius, Jason Yip, Owen Rodgers, Mike Roberts and many other open source contributors have participated in building some variant of CruiseControl. Although the tool isn't essential, many teams find it helpful. Cruise has played a big part in popularizing and enabling software developers to use Continuous Integration.

    One of the reasons I work at ThoughtWorks is to get good access to practical projects done by talented people. Nearly every project I've visited has given tasty morsels of continuous integration information. Significant Revisions

    01 May 06: Complete rewrite of article to bring it up to date and to clarify the description of the approach.

    10 Sep 00: Original version published.

  • Continuous Integration at 2008年06月19日

    The manual build approach is the simplest one to describe. Essentially it's a similar thing to the local build that a developer does before the commit into the repository. The developer goes to the integration machine, checks out the head of the mainline (which now houses his last commit) and kicks off the integration build. He keeps an eye on its progress, and if the build succeeds he's done with his commit. (Also see Jim Shore's description.)

    A continuous integration server acts as a monitor to the repository. Every time a commit against the repository finishes the server automatically checks out the sources onto the integration machine, initiates a build, and notifies the committer of the result of the build. The committer isn't done until she gets the notification - usually an email.

    At ThoughtWorks, we're big fans of continuous integration servers - indeed we led the development of CruiseControl and CruiseControl.NET, the widely used open-source CI servers. ThoughtWorkers like Paul Julius, Jason Yip, and Owen Rodgers are still active committers to these open source projects. We use CruiseControl on nearly every project we do and have been very happy with the results.

    Not everyone prefers to use a CI server. Jim Shore gave a well argued description of why he prefers the manual approach. I agree with him that CI is much more than just installing CruiseControl. All the practices here need to be in play to do Continuous Integration effectively. But equally many teams who do CI well find CruiseControl a helpful tool.

    Many organizations do regular builds on a timed schedule, such as every night. This is not the same thing as a continuous build and isn't enough for continuous integration. The whole point of continuous integration is to find problems as soon as you can. Nightly builds mean that bugs lie undetected for a whole day before anyone discovers them. Once they are in the system that long, it takes a long time to find and remove them.

    A key part of doing a continuous build is that if the mainline build fails, it needs to be fixed right away. The whole point of working with CI is that you're always developing on a known stable base. It's not a bad thing for the mainline build to break, although if it's happening all the time it suggests people aren't being careful enough about updating and building locally before a commit. When the mainline build does break, however, it's important that it gets fixed fast. To help avoid breaking the mainline you might consider using a pending head.

    When teams are introducing CI, often this is one of the hardest things to sort out. Early on a team can struggle to get into the regular habit of working mainline builds, particularly if they are working on an existing code base. Patience and steady application does seem to regularly do the trick, so don't get discouraged. Keep the Build Fast

    The whole point of Continuous Integration is to provide rapid feedback. Nothing sucks the blood of a CI activity more than a build that takes a long time. Here I must admit a certain crotchety old guy amusement at what's considered to be a long build. Most of my colleagues consider a build that takes an hour to be totally unreasonable. I remember teams dreaming that they could get it so fast - and occasionally we still run into cases where it's very hard to get builds to that speed.

    For most projects, however, the XP guideline of a ten minute build is perfectly within reason. Most of our modern projects achieve this. It's worth putting in concentrated effort to make it happen, because every minute you reduce off the build time is a minute saved for each developer every time they commit. Since CI demands frequent commits, this adds up to a lot of time.

    If you're staring at a one hour build time, then getting to a faster build may seem like a daunting prospect. It can even be daunting to work on a new project and think about how to keep things fast. For enterprise applications, at least, we've found the usual bottleneck is testing - particularly tests that involve external services such as a database.

    Probably the most crucial step is to start working on setting up a staged build. The idea behind a staged build (also known as build pipeline) is that there are in fact multiple builds done in sequence. The commit to the mainline triggers the first build - what I call the commit build. The commit build is the build that's needed when someone commits to the mainline. The commit build is the one that has to be done quickly, as a result it will take a number of shortcuts that will reduce the ability to detect bugs. The trick is to balance the needs of bug finding and speed so that a good commit build is stable enough for other people to work on.

    Once the commit build is good then other people can work on the code with confidence. However there are further, slower, tests that you can start to do. Additional machines can run further testing routines on the build that take longer to do.

    A simple example of this is a two stage build. The first stage would do the compilation and run tests that are more localized unit tests with the database completely stubbed out. Such tests can run very fast, keeping within the ten minute guideline. However any bugs that involve larger scale interactions, particularly those involving the real database, won't be found. The second stage build runs a different suite of tests that do hit the real database and involve more end-to-end behavior. This suite might take a couple of hours to run.

    In this scenario people use the first stage as the commit build and use this as their main CI cycle. The second-stage build is a secondary build which runs when it can, picking up the latest good commit build for further testing. If the secondary build fails, then this doesn't have the same 'stop everything' quality, but the team does aim to fix such bugs as rapidly as possible, while keeping the commit build running. Indeed the secondary build doesn't have to stay good, as long as each known bug is identified and dealt with in a next few days.

    If the secondary build detects a bug, that's a sign that the commit build could do with another test. As much as possible you want to ensure that any secondary build failure leads to new tests in the commit build that would have caught the bug, so the bug stays fixed in the commit build. This way the commit tests are strengthened whenever something gets past them. There are cases where there's no way to build a fast-running test that exposes the bug, so you may decide to only test for that condition in the secondary build. Most of time, fortunately, you can add suitable tests to the commit build.

    This example is of a two-stage build, but the basic principle can be extended to any number of later builds. The builds after the commit build can also be done in parallel, so if you have two hours of secondary tests you can improve responsiveness by having two machines that run half the tests each. By using parallel secondary builds like this you can introduce all sorts of further automated testing, including performance testing, into the regular build process. (I've run into a lot of interesting techniques around this as I've visited various ThoughtWorks projects over the last couple of years - I'm hoping to persuade some of the developers to write these up.) Test in a Clone of the Production Environment

    The point of testing is to flush out, under controlled conditions, any problem that the system will have in production. A significant part of this is the environment within which the production system will run. If you test in a different environment, every difference results in a risk that what happens under test won't happen in production.

    As a result you want to set up your test environment to be as exact a mimic of your production environment as possible. Use the same database software, with the same versions, use the same version of operating system. Put all the appropriate libraries that are in the production environment into the test environment, even if the system doesn't actually use them. Use the same IP addresses and ports, run it on the same hardware.

    Well, in reality there are limits. If you're writing desktop software it's not practicable to test in a clone of every possible desktop with all the third party software that different people are running. Similarly some production environments may be prohibitively expensive to duplicate (although I've often come across false economies by not duplicating moderately expensive environments). Despite these limits your goal should still be to duplicate the production environment as much as you can, and to understand the risks you are accepting for every difference between test and production.

    If you have a pretty simple setup without many awkward communications, you may be able to run your commit build in a mimicked environment. Often, however, you need to use test doubles because systems respond slowly or intermittently. As a result it's common to have a very artificial environment for the commit tests for speed, and use a production clone for secondary testing.

    I've noticed a growing interest in using virtualization to make it easy to put together test environments. Virtualized machines can be saved with all the necessary elements baked into the virtualization. It's then relatively straightforward to install the latest build and run tests. Furthermore this can allow you to run multiple tests on one machine, or simulate multiple machines in a network on a single machine. As the performance penalty of virtualization decreases, this option makes more and more sense. Make it Easy for Anyone to Get the Latest Executable

  • Continuous Integration at 2008年06月19日

    If a clash occurs between two developers, it is usually caught when the second developer to commit builds their updated working copy. If not the integration build should fail. Either way the error is detected rapidly. At this point the most important task is to fix it, and get the build working properly again. In a Continuous Integration environment you should never have a failed integration build stay failed for long. A good team should have many correct builds a day. Bad builds do occur from time to time, but should be quickly fixed.

    The result of doing this is that there is a stable piece of software that works properly and contains few bugs. Everybody develops off that shared stable base and never gets so far away from that base that it takes very long to integrate back with it. Less time is spent trying to find bugs because they show up quickly. Practices of Continuous Integration

    The story above is the overview of CI and how it works in daily life. Getting all this to work smoothly is obviously rather more than that. I'll focus now on the key practices that make up effective CI. Maintain a Single Source Repository.

    Software projects involve lots of files that need to be orchestrated together to build a product. Keeping track of all of these is a major effort, particularly when there's multiple people involved. So it's not surprising that over the years software development teams have built tools to manage all this. These tools - called Source Code Management tools, configuration management, version control systems, repositories, or various other names - are an integral part of most development projects. The sad and surprising thing is that they aren't part of all projects. It is rare, but I do run into projects that don't use such a system and use some messy combination of local and shared drives.

    So as a simple basis make sure you get a decent source code management system. Cost isn't an issue as good quality open-source tools are available. The current open source repository of choice is Subversion. (The older open-source tool CVS is still widely used, and is much better than nothing, but Subversion is the modern choice.) Interestingly as I talk to developers I know most commercial source code management tools are liked less than Subversion. The only tool I've consistently heard people say is worth paying for is Perforce.

    Once you get a source code management system, make sure it is the well known place for everyone to go get source code. Nobody should ever ask "where is the foo-whiffle file?" Everything should be in the repository.

    Although many teams use repositories a common mistake I see is that they don't put everything in the repository. If people use one they'll put code in there, but everything you need to do a build should be in there including: test scripts, properties files, database schema, install scripts, and third party libraries. I've known projects that check their compilers into the repository (important in the early days of flaky C++ compilers). The basic rule of thumb is that you should be able to walk up to the project with a virgin machine, do a checkout, and be able to fully build the system. Only a minimal amount of things should be on the virgin machine - usually things that are large, complicated to install, and stable. An operating system, Java development environment, or base database system are typical examples.

    You must put everything required for a build in the source control system, however you may also put other stuff that people generally work with in there too. IDE configurations are good to put in there because that way it's easy for people to share the same IDE setups.

    One of the features of version control systems is that they allow you to create multiple branches, to handle different streams of development. This is a useful, nay essential, feature - but it's frequently overused and gets people into trouble. Keep your use of branches to a minimum. In particular have a mainline: a single branch of the project currently under development. Pretty much everyone should work off this mainline most of the time. (Reasonable branches are bug fixes of prior production releases and temporary experiments.)

    In general you should store in source control everything you need to build anything, but nothing that you actually build. Some people do keep the build products in source control, but I consider that to be a smell - an indication of a deeper problem, usually an inability to reliably recreate builds. Automate the Build

    Getting the sources turned into a running system can often be a complicated process involving compilation, moving files around, loading schemas into the databases, and so on. However like most tasks in this part of software development it can be automated - and as a result should be automated. Asking people to type in strange commands or clicking through dialog boxes is a waste of time and a breeding ground for mistakes.

    Automated environments for builds are a common feature of systems. The Unix world has had make for decades, the Java community developed Ant, the .NET community has had Nant and now has MSBuild. Make sure you can build and launch your system using these scripts using a single command.

    A common mistake is not to include everything in the automated build. The build should include getting the database schema out of the repository and firing it up in the execution environment. I'll elaborate my earlier rule of thumb: anyone should be able to bring in a virgin machine, check the sources out of the repository, issue a single command, and have a running system on their machine.

    Build scripts come in various flavors and are often particular to a platform or community, but they don't have to be. Although most of our Java projects use Ant, some have used Ruby (the Ruby Rake system is a very nice build script tool). We got a lot of value from automating an early Microsoft COM project with Ant.

    A big build often takes time, you don't want to do all of these steps if you've only made a small change. So a good build tool analyzes what needs to be changed as part of the process. The common way to do this is to check the dates of the source and object files and only compile if the source date is later. Dependencies then get tricky: if one object file changes those that depend on it may also need to be rebuilt. Compilers may handle this kind of thing, or they may not.

    Depending on what you need, you may need different kinds of things to be built. You can build a system with or without test code, or with different sets of tests. Some components can be built stand-alone. A build script should allow you to build alternative targets for different cases.

    Many of us use IDEs, and most IDEs have some kind of build management process within them. However these files are always proprietary to the IDE and often fragile. Furthermore they need the IDE to work. It's okay for IDE users set up their own project files and use them for individual development. However it's essential to have a master build that is usable on a server and runnable from other scripts. So on a Java project we're okay with having developers build in their IDE, but the master build uses Ant to ensure it can be run on the development server. Make Your Build Self-Testing

    Traditionally a build means compiling, linking, and all the additional stuff required to get a program to execute. A program may run, but that doesn't mean it does the right thing. Modern statically typed languages can catch many bugs, but far more slip through that net.

    A good way to catch bugs more quickly and efficiently is to include automated tests in the build process. Testing isn't perfect, of course, but it can catch a lot of bugs - enough to be useful. In particular the rise of Extreme Programming (XP) and Test Driven Development (TDD) have done a great deal to popularize self-testing code and as a result many people have seen the value of the technique.

    Regular readers of my work will know that I'm a big fan of both TDD and XP, however I want to stress that neither of these approaches are necessary to gain the benefits of self-testing code. Both of these approaches make a point of writing tests before you write the code that makes them pass - in this mode the tests are as much about exploring the design of the system as they are about bug catching. This is a Good Thing, but it's not necessary for the purposes of Continuous Integration, where we have the weaker requirement of self-testing code. (Although TDD is my preferred way of producing self-testing code.)

    For self-testing code you need a suite of automated tests that can check a large part of the code base for bugs. The tests need to be able to be kicked off from a simple command and to be self-checking. The result of running the test suite should indicate if any tests failed. For a build to be self-testing the failure of a test should cause the build to fail.

    Over the last few years the rise of TDD has popularized the XUnit family of open-source tools which are ideal for this kind of testing. XUnit tools have proved very valuable to us at ThoughtWorks and I always suggest to people that they use them. These tools, pioneered by Kent Beck, make it very easy for you to set up a fully self-testing environment.

    XUnit tools are certainly the starting point for making your code self-testing. You should also look out for other tools that focus on more end-to-end testing, there's quite a range of these out there at the moment including FIT, Selenium, Sahi, Watir, FITnesse, and plenty of others that I'm not trying to comprehensively list here.

    Of course you can't count on tests to find everything. As it's often been said: tests don't prove the absence of bugs. However perfection isn't the only point at which you get payback for a self-testing build. Imperfect tests, run frequently, are much better than perfect tests that are never written at all. Everyone Commits Every Day

    Integration is primarily about communication. Integration allows developers to tell other developers about the changes they have made. Frequent communication allows people to know quickly as changes develop.

    The one prerequisite for a developer committing to the mainline is that they can correctly build their code. This, of course, includes passing the build tests. As with any commit cycle the developer first updates their working copy to match the mainline, resolves any conflicts with the mainline, then builds on their local machine. If the build passes, then they are free to commit to the mainline.

    By doing this frequently, developers quickly find out if there's a conflict between two developers. The key to fixing problems quickly is finding them quickly. With developers committing every few hours a conflict can be detected within a few hours of it occurring, at that point not much has happened and it's easy to resolve. Conflicts that stay undetected for weeks can be very hard to resolve.

    The fact that you build when you update your working copy means that you detect compilation conflicts as well as textual conflicts. Since the build is self-testing, you also detect conflicts in the running of the code. The latter conflicts are particularly awkward bugs to find if they sit for a long time undetected in the code. Since there's only a few hours of changes between commits, there's only so many places where the problem could be hiding. Furthermore since not much has changed you can use diff-debugging to help you find the bug.

    My general rule of thumb is that every developer should commit to the repository every day. In practice it's often useful if developers commit more frequently than that. The more frequently you commit, the less places you have to look for conflict errors, and the more rapidly you fix conflicts.

    Frequent commits encourage developers to break down their work into small chunks of a few hours each. This helps track progress and provides a sense of progress. Often people initially feel they can't do something meaningful in just a few hours, but we've found that mentoring and practice helps them learn. Every Commit Should Build the Mainline on an Integration Machine

    Using daily commits, a team gets frequent tested builds. This ought to mean that the mainline stays in a healthy state. In practice, however, things still do go wrong. One reason is discipline, people not doing an update and build before they commit. Another is environmental differences between developers' machines.

    As a result you should ensure that regular builds happen on an integration machine and only if this integration build succeeds should the commit be considered to be done. Since the developer who commits is responsible for this, that developer needs to monitor the mainline build so they can fix it if it breaks. A corollary of this is that you shouldn't go home until the mainline build has passed with any commits you've added late in the day.

    There are two main ways I've seen to ensure this: using a manual build or a continuous integration server.

  • 持续集成 at 2008年06月19日

    对于下列 “成功创建” 的标准,我们还是相当自信的:

    * 所有最新的源代码都被配置管理系统验证合格 * 所有文件都通过重新编译 * 得到的目标文件(在我们这里就是 Java 的 class 文件)都通过连接,得到可执行文件 * 系统开始运行,针对系统的测试套件(在我们这里大概有 150 个测试类)开始运行 * 如果所有的步骤都没有错误、没有人为干涉,所有的测试也都通过了,我们就得到了一个成功的创建

    绝大多数人都认为 “编译 + 连接=创建”。至少我们认为:创建还应该包括启动应用程序、针对应用程序运行简单测试(McConnell 称之为 “冒烟测试”:打开开关让软件运行,看它是否会 “冒烟”)。运行更详尽的测试集可以大大提高持续集成的价值,所以我们会首选更详尽的测试。

    单一代码源 为了实现每日集成,任何开发者都需要能够很容易地获取全部最新的源代码。以前,如果要做一次集成,我们就必须跑遍整个开发中心,询问每一个程序员有没有新的代码,然后把这些新代码拷贝过来,再找到合适的插入位置……没有什么比这更糟糕的了。

    办法很简单。任何人都应该可以带一台干净的机器过来,连上局域网,然后用一条命令就得到所有的源文件,马上开始系统的创建。

    最简单的解决方案就是:用一套配置管理(源代码控制)系统作为所有代码的来源。配置管理系统通常都设计有网络功能,并且带有让开发者轻松获取源代码的工具。而且,它们还提供版本管理工具,这样你可以很轻松地找到文件以前的版本。成本就更不成问题了,CVS 就是一套出色的开放源代码的配置管理工具。

    所有的源文件都应该保存在配置管理系统中。我说的这个 “所有” 常常比人们想到的还要多,它还包括创建脚本、属性文件、数据库调度 DLL、安装脚本、以及在一台干净的机器上开始创建所需的其他一切东西。经常都能看到这样的情况:代码得到了控制,但是其他一些重要的文件却找不到了。

    尽量确保所有的东西都保存在配置管理系统的同一棵代码源树中。有时候为了得到不同的组件,人们会使用配置管理系统中不同的项目。这带来的麻烦就是:人们不得不记住哪个组件的哪个版本使用了其他组件的哪些版本。在某些情况下,你必须将代码源分开,但是这种情况出现的几率比你想象的要小得多。你可以在从一棵代码源树创建多个组件,上面那些问题可以通过创建脚本来解决,而不必改变存储结构。

    自动化创建脚本 如果你编写的是一个小程序,只有十几个文件,那么应用程序的创建可能只是一行命令的事:javac *.java。更大的项目就需要更多的创建工作:你可能把文件放在许多目录里面,需要确保得到的目标代码都在适当的位置;除了编译,可能还有连接的步骤;你可能还从别的文件中生成了代码,在编译之前需要先生成;测试也需要自动运行。

    大规模的创建经常会耗费一些时间,如果只做了一点小小的改动,当然你不会希望重新做所有这些步骤。所以好的创建工具会自动分析需要改变的部分,常见的方法就是检查源文件和目标文件的修改日期,只有当源文件的修改日期迟于目标文件时,才会重新编译。于是,文件之间的依赖就需要一点技巧了:如果一个目标文件发生了变化,那么只有那些依赖它的目标文件才会重新编译。编译器可能会处理这类事情,也可能不会。

    取决于自己的需要,你可以选择不同的创建类型:你创建的系统可以有测试代码,也可以没有,甚至还可以选择不同的测试集;一些组件可以单独创建。创建脚本应该让你可以根据不同的情况选择不同的创建目标。

    你输入一行简单的命令之后,帮你挑起这副重担常常是脚本。你使用的可能是 shell 脚本,也可能是更复杂的脚本语言(例如 Perl 或 Python)。但是很快你就会发现一个专门设计的创建环境是很有用的,例如 Unix 下的 make 工具。

    在我们的 Java 开发中,我们很快就发现需要一个更复杂的解决方案。Matt 用了相当多的时间开发了一个用于企业级 Java 开发的创建工具,叫做 Jinx。但是,最近我们已经转而使用开放源代码的创建工具 Ant(http: //jakarta.apache.org/ant/index.html)。Ant 的设计与 Jinx 非常相似,也支持 Java 文件编译和 Jar 封装。同时,编写 Ant 的扩展也很容易,这让我们可以在创建过程中完成更多的任务。

    许多人都使用 IDE,绝大多数的 IDE 中都包含了创建管理的功能。但是,这些文件都依赖于特定的 IDE,而且经常比较脆弱,而且还需要在 IDE 中才能工作。IDE 的用户可以建立自己的项目文件,并且在自己的单独开发中使用它们。但是我们的主创建过程用 Ant 建立,并且在一台使用 Ant 的服务器上运行。

    自测试的代码 只让程序通过编译还是远远不够的。尽管强类型语言的编译器可以指出许多问题,但是即使成功通过了编译,程序中仍然可能留下很多错误。为了帮助跟踪这些错误,我们非常强调自动化测试——这也是 XP 提倡的另一个实践。

    XP 将测试分为两类:单元测试和容纳测试(也叫功能测试)。单元测试是由开发者自己编写的,通常只测试一个类或一小组类。容纳测试通常是由客户或外部的测试组在开发者的帮助下编写的,对整个系统进行端到端的测试。这两种测试我们都会用到,并且尽量提高测试的自动化程度。

    作为创建的一部分,我们需要运行一组被称为 “BVT”(Build Verification *,创建确认测试)的测试。BVT 中所有的测试都必须通过,然后我们才能宣布得到了一个成功的创建。所有 XP 风格的单元测试都属于 BVT。由于本文是关于创建过程的,所以我们所说的 “测试” 基本上都是指 BVT。请记住,除了 BVT 之外,还有一条测试线存在(译注:指功能测试),所以不要把 BVT 和整体测试、QA 等混为一谈。实际上,我们的 QA 小组根本不会看到没有通过 BVT 的代码,因为他们只对成功的创建进行测试。

    有一条基本的原则:在编写代码的同时,开发者也应该编写相应的测试。完成任务之后,他们不但要归还(check in)产品代码,而且还要归还这些代码的测试。这也跟 XP 的 “测试第一” 的编程风格很相似:在编写完相应的测试、并看到测试失败之前,你不应该编写任何代码。所以,如果想给系统添加新特性,你首先应该编写一个测试。只有当新的特性已经实现了以后,这个测试才可能通过。然后,你的工作就是让这个测试能够通过。

    我们用 Java 编写这些测试,与开发使用同样的语言,所以编写测试与编写代码没有太大的区别。我们使用 JUnit(http: //www.junit.org/)来作为组织、编写测试的框架。JUnit 是一个简单的框架,让我们可以快速编写测试、将测试组织为套件、并以交互或批处理的模式来运行测试套件。(JUnit 是 xUnit 家族的 Java 版本——xUnit 包括了几乎所有语言的测试框架。)

    在编写软件的过程中,在每一次的编译之后,开发者通常都会运行一部分单元测试。这实际上提高了开发者的工作效率,因为这些单元测试可以帮助你发现代码中的逻辑错误。然后,你就没必要去调试查错,只需要注意最后一次运行测试之后修改的代码就行了。这个修改的范围应该很小,所以寻找 bug 也就容易多了。

    并非所有的人都严格遵循 XP“测试第一” 的风格,但是在第一时间编写测试的好处是显而易见的。它们不但让每个人的工作效率更高,而且由这些测试构成的 BVT 更能捕捉到系统中的错误。因为 BVT 每天要运行好几次,所以 BVT 检查出的任何问题都是比较容易改正的,原因很简单:我们只做了相当小范围的修改,所以我们可以在这个范围内寻找 bug。在修改过的一小块代码中排错当然比跟踪整个系统来排错要有效多了。

    当然,你不能指望测试帮你找到所有的问题。就象人们常说的:测试不能证明系统中不存在错误。但是,尽善尽美不是我们唯一的要求。不够完美的测试只要经常运行,也比永远写不出来的 “完美测试” 要好得多。

    另一个相关的问题就是:开发者们为自己的代码编写测试。我们经常听人说:开发者不应该测试自己的代码,因为他们很容易忽视自己工作中的错误。尽管这也是事实,但是自测试过程需要快速将测试转入代码基础中。这种快速转换的价值超过独立测试者的价值。所以,我们还是用开发者自己编写的测试来构造 BVT,但是仍然有独立编写的容纳测试。

    自测试另一个很重要的部分就是它通过反馈——XP 的一项核心价值——来提高测试的质量。这里的反馈来自于从 BVT 中逃脱的 bug。自测试的规则是:除非你在 BVT 中加入了相应的测试,否则就不能修正任何错误。这样,每当要修正某个错误的时候,你都必须添加相应的测试,以确保 BVT 不会再把错误放过去。而且,这个测试应该引导你去考虑更多的测试、编写更多的测试来加强 BVT。

    主创建 创建过程的自动化对于单个开发者来说很有意义,但是它真正发光的,还是在整个系统的主创建(master build)的生成。我们发现,主创建过程能让整个团队走到一起来,让他们及早发现集成中的问题。

    第一步是要选择运行主创建的机器。我们选择了一台叫做 “投石车” 的计算机(我们经常玩 “帝国时代” J),这是一台装有四个 CPU 的服务器,非常适合专门用来做创建。(由于完整的创建需要相当长的时间,所以这种马力是必须的。)

    创建进程是在一个随时保持运行的 Java 类中进行的。如果没有创建任务,创建进程就一直循环等待,每过几分钟去检查一下代码仓库。如果在最后的创建之后没有人归还任何代码,进程就继续等待。如果代码仓库中有了新的代码,就开始创建。

    创建的第一阶段是完全提取仓库中的代码。Starteam 已经为我们提供了相当好的 Java API,所以切入代码仓库也很容易。守护进程(daemon)会观察五分钟以前的仓库,看最近五分钟里面有没有人归还了代码。如果有,守护进程就会考虑等五分钟再提取代码(以免在别人归还代码的过程中提取)。

    守护进程将全部代码提取到投石机的一个目录中。提取完成之后,守护进程就会在这个目录里调用 Ant 脚本。然后,Ant 会接管整个创建过程,对所有源代码做一次完整的创建。Ant 脚本会负责整个编译过程,并把得到的 class 文件放进六个 jar 包里,发布到 EJB 服务器上。

    当 Ant 完成了编译和发布的工作之后,创建守护进程就会在 EJB 服务器上开始运行新的 jar,同时开始运行 BVT 测试套件。如果所有的测试都能正常运行通过,我们就得到了一个成功的创建。然后创建守护进程就会回到 Starteam,将所有提取出的源代码标记上创建号。然后,守护进程会观察创建过程中是否还有人归还了代码。如果有,就再开始一次创建;如果没有,守护进程就回到它的循环中,等待下一次的归还。

    创建结束之后,创建守护进程会给所有向最新一次创建归还了代码的开发者发一个 e-mail,汇报创建的情况。如果把创建留在代码归还之后去做,而又不用 e-mail 向开发者通报创建的情况,我们通常认为这是不好的组织形式。

    守护进程将所有的步骤都写在 XML 格式的日志文件里面。投石车上会运行一个 servlet,允许任何人通过它检查日志,以观察创建的状态。(见图 1)

    屏幕上会显示出创建是否正在运行、开始运行的时间。在左边有所有创建的历史记录,成功的、失败的都记录在案。点击其中的某一条记录,就会显示出这次创建的详细信息:编译是否通过、测试的结果、发生了哪些变化……

    我们发现很多开发者都经常看看这个页面,因为它让他们看到项目发展的方向,看到随着人们不断归还代码而发生的变化。有时我们也会在这个页面上放一些其他的项目新闻,但是需要把握好尺度。

    要让开发者能在自己的本地机器上模拟主创建过程,这是很重要的。这样,如果集成错误出现了,开发者可以在自己的机器上研究、调试,而不必真的执行主创建过程。而且,开发者也可以在归还代码之前先在本地执行创建,从而降低了主创建失败的可能性。

    这里有一个比较重要的问题:主创建应该是干净的创建(完全从源代码开始)还是增量创建?增量创建会快得多,但是也增大了引入错误的风险,因为有些部分是没有编译的。而且我们还有无法重新创建的风险。我们的创建速度相当快(20 万行代码约 15 分钟),所以我们乐于每次都做干净的创建。但是,有些团队喜欢在大多数时候做增量创建,但是当那些奇怪的问题突然出现时,也经常性地做干净的创建(至少每天一次)。

    代码归还(Check in) 使用自动化创建就意味着开发者应该遵循某种节奏来开发软件,最重要的就是他们应该经常集成。我们曾经见过一些组织,他们也做日创建,但是其中的开发者却不经常归还代码。如果开发者几周才归还一次代码,那么日创建又有什么意义呢?我们遵循的原则是:每个开发者至少每天要归还一次代码。

    在开始新的任务之前,开发者应该首先与配置管理系统同步。也就是说,他们应该首先更新本地机器上的源代码。在旧的代码基础上编写代码,这只会带来麻烦和混乱。

    然后,开发者要随时保持文件的更新。开发者可以在一段任务完成之后将代码集成到整个系统中,也可以在任务的中途集成,但是在集成的时候必须保证所有的测试都能通过。

    集成的第一步是要再次使开发者的本地文件与代码仓库同步。代码仓库中所有新近有改动的文件都要拷贝到开发者的工作目录中来,当文件发生冲突时,配置管理系统会向开发者提出警告。然后,开发者需要对同步后的工作集进行创建,对这些文件运行 BVT,并得到正确的结果。

    现在,开发者可以把新的文件提交到代码仓库中。提交完成之后,开发者就需要等待主创建。如果主创建成功,那么这次归还也是成功的。如果主创建失败了,开发者可以在本地修改。如果修改很简单,就可以直接提交;如果修改比较复杂,开发者就需要放弃这次修改,重新同步自己的工作目录,然后继续在本地开发、调试,然后再次提交。

    某些系统强制要求归还进程逐个进行。在这种情况下,系统中会有一个创建令牌,同一时间只有一个开发者能拿到令牌。开发者获取创建令牌,再次同步文件,提交修改,然后释放令牌。这就确保创建过程中,最多只能有一个开发者在更新代码仓库。不过我们发现,即使没有创建令牌,我们也很少遇到麻烦,所以我们也不用这种方法。经常会有多个人同时向同一个主创建提交代码的情况,但是这很少造成创建失败,而且这样的错误也很容易修复。

    同时,我们还让开发者自己来决定归还过程中的小心程度。这反映出开发者对集成错误出现几率的评估。如果她觉得很有可能出现集成错误,那么她就会在归还之前先做一次本地创建;如果她觉得根本不可能出现集成错误,那么她可以直接归还。如果犯了错误,在主创建运行时她立刻就会发现,然后她就必须放弃自己的修改,找到出错的地方。如果错误很容易发现、很容易修补,那么这种错误也是可以接受的。

    总结 发展一个制度严密的自动化创建过程对于项目的控制是很重要的。许多软件先贤都这样说,但是我们发现,这样的过程在软件开发领域中仍然罕见。

    关键是要让所有的事情都完全自动化,并且要经常进行集成,这样才能尽快发现错误。然后,人们可以随时修改需要修改的东西,因为他们知道:如果他们做的修改引起了集成错误,那也是很容易发现和修补的。一旦获得了这些利益,你会发现自己再也无法放下它们。

    英文原文版权由 Martin Fowler 拥有 Original text is copyrighted by Martin Fowler 原文链接:[url]http://martinfowler.com/articles/continuousIntegration.html/url][

  • 新人上岗五大注意事项 at 2008年06月19日

    新人工作注意事项 一、多做事少说话。 二、不断提高工作效率。 三、定期评估和总结工作,提高工作效果。 四、敢于承担重要的工作。 五、避免错误,减少失误。 六、尊重老员工。 七、学会制作工作计划和及时完成计划。 八、节约。 九、注意个人卫生。 十、创新。 工作方法介绍:计划(设想)—实施(完成)—控制(环节)—调整(条件)—评估(成果)。

  •   华为公司总的来说是个内部很宽容的公司,不像社会上想象的那样。有些误解的人,主要是不了解我们,我也是可以理解的。千秋功罪,何必要评说呢?你何必要等到评说呢?没人会给你评说,你放心好了。你就好好珍惜自己,不要太多地听信闲言碎语,不要有太多的精神压力和包袱。   第二点,是大家要对经济全球化以及市场竞争的艰难性、残酷性做好充分的心理准备。   经济全球化是美国推出来的,美国最后看到经济全球化对美国并不有利,所以美国在退向贸易保护主义,但是保也保不住,经济全球化这个火烧起来了,就会越烧越旺。过去的一百多年,经济的竞争方式是以火车、轮船、电报、传真等手段来进行的,竞争强度是不大的,从而促进了资本主义在前一百多年,有序的、很好的获得发展。而现在,由于光纤与计算机的发展,形成网络经济,形成资源的全球化配置。使交付、服务更加贴近客户,快速而优质的服务;使制造更加贴近低成本;研发更加贴近人才集中的低成本地区……。这使竞争的强度大大增强,将会使优势企业越来越强,没优势的企业越来越困难。特别是电子产业将会永远的供过于求,困难的程度,是可以想象的。   经济全球化使得竞争越来越残酷了,特别是我们电子行业,竞争极其残酷。我就举个例子来看:电子产品的性能、质量越来越高,越来越需高素质人才,而且是成千上万,数万的需求,这些人必需有高的报酬才合理。但电子产品却越来越便宜。这就成了一个矛盾,如何得以解决,我们期待某一个经济学家,能获得电子经济诺贝尔奖。   我们仅是比其他公司对这个竞争残酷性早了一点点认识,我们才幸免于难。你们读书的时候都很崇拜贝尔实验室的吧?十多年前,我去贝尔实验室,当时 DWDM 还处在发明阶段,发明的一个波,就是 GW 载波,当时光纤还只能有三个载波,发明这项技术的博士亲自给我做图形表演。结果没多久光传输像排山倒海一样,迅速的形成过剩,把贝尔实验室也席卷了,大水冲了龙王庙。成则亦光,败则亦光。我们也在这里苟延残喘。我们的光传输产品,七、八年来降价了二十倍。市场经济的过剩就像绞杀战一样。绞杀战如什么呢?就如拧毛巾,这毛巾只要拧出水来,就说明还有竞争空间,毛巾拧断了企业也完了,只有毛巾拧干了,毛巾还不断,这才是最佳状态。华为公司能长久保持到这个状态吗?我这两天批了一个文件给业务口征求意见,我写了一段对话,我提到了思科,当然我是歌颂了钱伯斯,思科现在开始实行很多政策,如减少员工出差,减少会议,来提高效率,高层领导出差不能坐头等舱,要坐,须自己掏钱,等等这一系列的措施。思科尚且如此,华为就能独善其身?   支撑信息产业发展的两个要素,一是数码,取之不尽用之不竭,还不用缴任何专利费;二是二氧化硅,做硅片的。这两个东西取之不尽用之不竭的,导致电子产品过剩。过剩的结果就是大家都拧毛巾,绞杀战。西方公司过去日子太好了,拧的水太多了,所以拧着拧着把自己拧死了,我们也不是最佳状态。我们公司的铺张浪费还很多的。   在这种情况下,怎么办?当然我曾经悲观过啊,但是每次犯忧郁症的时候就是那种病态,但不是我的完整思想。我曾经很发愁,觉得苦闷啊。华为公司只要稍稍不行了,怎么发工资啊?我觉得这是很大的压力。我们不是悲观主义者,但也要对经济全球化以及市场竞争的残酷性要有充分的心理准备。如果华为衰落怎么办?如何才能不衰落呢?总有一天,别人在发展,而我们在落后的。   这个世界的变化是很大的,唯一不变的是变化。面对这样的变化,每个企业,如果不能奋起,最终就是灭亡,而且灭亡的速度很快。以前我们还有祖传秘方,比如说爷爷打菜刀打得很好,方圆五十里都知道我们家菜刀好,然后孙子继承了爷爷的手艺。在方圆五十里我还是优秀的铁匠,就能娶到了一朵金花啊。那现在铁匠还行吗?现在经济全球化啦。人家用碳纤维做的刀,削铁如泥,比钢刀还好得多。你在方圆几公里几十公里曾经流传几十年几百年的祖传,就被经济全球化在几秒钟内打得粉碎。所以在这样的情况下,就给每个人带来了生存的困难,所以每个人都要寻找生存的基点。   但是,竞争是好,还是坏?竞争使这个世界进步了,加速了,美好了。我们享受了这种美好。五十年前,我记得我上小学的时候还打赤脚,还穿草鞋。我的梦想就是穿一双橡胶底的鞋。你看现在好多人都开汽车了,五十年的变化是不可想像的。当年我在欧洲坐豪华的列车时,就想 “哎,中国这是没戏啰!” 我在美国坐了豪华大巴时,“哎,在中国可能我坐不上了,看不见了。” 中国在这么短的时间发展这么快,我想都没想到,社会进步是很快的,这个社会进步给每个人带来了美好,但是也带来了痛苦。WTO 是把物价降下来了,但是也让很多人失业了。   美国竞争失利是因为他们薪酬太高而失利,而不是因为华为的崛起使他们失败了。所以美国很多要人跟我交流,我就讲是你们失败是因为你们的薪酬点太高了,不可能这么高的薪酬,怎么可能啊?你们的薪酬从哪里来的?是从那些 GDP 只有 200 多个美金的非洲的弟兄们那儿取来的钱,来供这些 IT 皇帝们,能供得起吗?供不起的。最终有一天会支撑不起的。   我们要加强对员工的关怀。我最近不是讲了吗?我们 EMT 作的决定,就是对那些前线竞争进行投标、进行高强度作业、压力太大的员工,可以短时间到海滨去度假,费用由公司支付。还有一些奋斗强度太大,短时间身体不太好的,可以临时拖到五星级酒店缓冲一下。我们的国际救援都是一级救援的啊。我们买的是美国 AIA 的保险,我们每年为员工支付的各种保障费用大约是八个亿,我们员工在海外有意外,有直升飞机送到他们认证的医院去抢救,我们当然不希望这种事情发生。   我们希望大家要互相关爱,特别是各级党组织的支部书记、支委员,能不能跟员工交交朋友,跟他们谈谈心,吃顿饭?你想想,在非洲那么荒凉的地方,大家出去撮一顿,大家可能就增强了友谊,可能就是因为你跟他的友谊,他给你打了一个电话,你救了他一条命。所以我号召我们党组织要跟员工做朋友。当然我讲每级行政管理团队都要和员工有一个定时间的沟通,定一个时间,多长时间你们和员工有一个沟通,十分钟、十五分钟都是可以的,你要沟通。在调动工作时,主管一定要和本人做沟通,不能什么都不告诉他,简单命令一下,这样草率,草菅人命,不好。这种东西容易引起很多矛盾。其实很多事情并不是这样子,讲清楚就好了。所以我讲的就是希望大家互相关爱,这种关爱精神一定要有。这样可以平缓竞争给人们带来的心理压力。   第三点,如何面对当前的形势,如何面对竞争对手,我们应该怎么办?   其实就是必须继续努力,要一天比一天有一点点进步。我们没有奋斗的终极目标,不奋斗是没有出路的。不管形势如何变化,只要我们团结合作,紧张而镇定,总会有活路的。同时我们也不要仅为自己生存,而去做一些不应该做的行为。我们要做一个国际市场秩序的维护者,而不是一个破坏者。我们要遵循这些规律,而不是颠覆这些规律。我们要积极地向强者学习,尊重他们的市场领导地位,积极、但有序地开展竞争,以激活双方的组织体系,实现共赢。   近几年,我国的经济形势也可能出现下滑,希望高级干部要有充分的心理准备。也许 2009 年、2010 年还会更加困难。宏观经济不好,对我们员工来说应该不会有太大的影响,但对你们的家庭可能有很多困难。比如说肉涨价啦,奶粉涨价啦,大米涨价啦,都会带来你周围的亲戚、朋友的困难。我们应该怎么办?   我要讲的是,一定要理解国家在这个变革时期的困难。中国这三十年来的变化是巨大的,国家的富强是我们想象都想象不到的。但快速发展的经济,也不可能持久不变,也会遇到调整。中国历史上走过的路都是弯弯曲曲走过来的,右一阵子左一阵子,左一阵子右一阵子,但是它总的还是在往前走,所以我们对 “左一阵子右一阵子” 要忍耐。不要去发表任何不负责任的言论,更不要 “指点江山,激扬文字”。我们一定要有忍耐!我为什么有点担心呢?担心社会可能不忍耐。如果社会不能忍耐,出了乱子的时候,我们应严格要求员工,不准发表任何政治言论,更不允许上街去参加什么活动。去年经济好的时候,你讲的话出格就算啦,没关系,现在不要讲了。关键时刻你不能发表任何讲话,给社会添麻烦。要保持与党和国家一致,千万不要在这个时候拆国家的台。国家也很难。我们态度讲清楚:你乱发表言论,你上街游行,我们是要辞退的。但,你的退职金还是要发给你的。   要有一个思想准备,不见得我们是这么平安,这么平稳的。千万不要以为自己能改变这个世界,其实我们才是幼稚可笑的,不要有太多幻想。努力做好你们的份内工作,就是对这个国家最大的忠诚。我们会处于一个敏感的政治时期。这个时期特别是党员要带头,与党和国家保持一致。也可能这个时候,可能在很多问题上有自己的见解,我认为这都是可能的,但是你的行为必须要被约束。

  • NAnt 入门手册 at 2008年06月18日

    Projects

    一个工程有如下属性:

    属性 描述 是否 必须 name 工程的名字 否 default 设置缺省对象,当命令行中没有指定对象时,缺省的对象将被执行 否 basedir 基本目录.从这个目录开始,计算所有的路径,如果不设置,build 文件的父目录将被使用. 否

    可以在顶层元素中对工程加以描述,使用命令行-projecthelp 的时候将使用这个描述,可以参见 build 文件一节中的详细介绍.

    可以在顶层元素中对工程加以描述,使用命令行-projecthelp 的时候将使用这个描述,可以参见 build 文件一节中的详细介绍.

    每一个工程定义了 0 个或多个对象,每个对象是将被执行的一组任务,当 nant 运行的时候,你可以指定想要执行的对象,没有对象指定时,默认对象将被执行;当两者都没有时,仅仅执行工程的 global tasks.

  • NAnt 入门手册 at 2008年06月18日

    Build 文件

    Nant 的 Build 文件是用 xml 写的。每一个文件包含一个工程(project)和几个对象(target),每一个对象包含几个任务(taek)。下面是一个编译 HelloWorld(c#)工程的简单 build 文件。

    <?xml version="1.0"?> The Hello World of build files.

    在这个例子里面,有"clean" and "build". 两个对象。缺省时,“build” 任务会被调用。 例子

    在 examples 文件夹内,你能找到运行这些粒子所需的文件。

    nant:在 debug 模式(缺省)下运行 nant 并构建工程。

    nant clean:运行 nant 并删除已编译好的文件。

    nant -D:debug=false:在 non-debug 模式下运行 nant 并生成工程。尽管 build 文件的 debug 属性为真(true),命令行中设置的值不会受影响,就像 任务中的 “overwrite” 属性被设置为假(false)。

    重要提示:如果产生的文件的日期比源文件的日期早,将仅仅执行像编译器任务这样的任务。如果你在 debug 模式下编译 HelloWorld 工程,然后什么东西也不清除,在 no-debug 模式下重新编译,这种情况就会发生,因为 nant 工程不需要被重新生成。