源文件下载地址:http://python.net/~gherman/projects/buildpkg/
当前记录版本号为: 0.3
Readme
############################################################################################################
Readme
buildpkg.py -- A Python tool to build OS X packages for Apple's Installer.app.
Purpose
This is a Python tool for building packages to be installed with the Mac OS X Installer.app application. It is much inspired by Apple's GUI tool called PackageMaker.app, which is part of the OS X developer tools installed in /Developer/Applications. There are other free GUI tools to do the same thing (1), (2). This tool has no GUI which is a feature and not a bug.
Version
The current version is 0.3.
License
The current license for this version is the "BSD License" as described by the Open Source Initiative (7).
About Apples's Installer.app
Apple has defined its own format for software packages to be installed on an OS X system. This format stems originally from the Mach/NeXTSTEP operating system of which OS X is a direct successor. The shape of such a package is basically a set of nested directories with the top-level one having the extension .pkg (or .mpkg). It contains one archive compressed with "pax", plus a set of further files describing the package content, plus additional optional scripts to be run during installation. Unfortunately, Apple does not fully document all features of its Installer or announces changes in the package layout.
Features of buildpkg.py
The essential work performed by buildpkg.py for a new package named <PACKAGE> is to:
- create a package directory <PACKAGE>.pkg/ plus its entire layout (subdirectories)
- add a file <PACKAGE>.pkg/<PACKAGE>.info containing the installation options
- add "bill of materials" file <PACKAGE>.pkg/<PACKAGE>.bom (using "mkbom")
- add the source root directory as <PACKAGE>.pkg/<PACKAGE>.pax.gz
- add optional resources to <PACKAGE>.pkg/Contents/Resources
- add a file <PACKAGE>.pkg/<PACKAGE>.sizes indicating the total size of the installed package
Among the optional resource files there are the Welcome, ReadMe and License files (either in .txt, .rtf, .rtfd/ or .html format) shown during installation. These can also be inside localization bundles, like English.lproj/ or German.lproj/). Other resources will mostly be installation scripts (e.g. preflight, <PACKAGE>.{pre,post}-{upgrade,install}, postflight, and probably others as well) called by the installer at the appropriate moment.
buildpkg.py does not try to be smart enough to filter only the relevant files from the resources you indicate. It simply copies them into the package.
Command-line usage
The intended use of the buildpkg.py script is both, as a command-line tool and as a Python module which can be imported in other Python programs (with "distutils" being the most obvious Python candidate package).
- Call the program without any options/arguments
darwin% python buildpkg.py
No argument given!
Usage: buildpkg.py <opts1> [<opts2>] <root> [<resources>]
with arguments:
(mandatory) root: the package root folder
(optional) resources: the package resources folder
and options:
(mandatory) opts1:
--Title
--Version
--Description
(optional) opts2: (with default values)
--Application: 'NO'
--DefaultLocation: '/'
--DeleteWarning: ''
--DisableStop: 'NO'
--Diskname: '(null)'
--InstallFat: 'NO'
--InstallOnly: 'NO'
--NeedsAuthorization: 'NO'
--Relocatable: 'YES'
--Required: 'NO'
--RequiresReboot: 'NO'
--UseUserMask: 'YES'
- Call the program with only the mandatory options and arguments
darwin% python buildpkg.py --Title=readline-4.3 --Version=4.3\
--Description="GNU Readline Library" /my/space/readline-4.3
- As above but with additional option --RequiresReboot YES
darwin% python buildpkg.py --Title=readline-4.3 --Version=4.3\
--Description="GNU Readline Library" --RequiresReboot YES\
/my/space/readline-4.3
- As above but with additional resources directory argument (will copy its content into /my/space/readline-4.3/pkg/Contents/Resources/)
darwin% python buildpkg.py --Title=readline-4.3 --Version=4.3\
--Description="GNU Readline Library" --RequiresReboot YES\
/my/space/readline-4.3 /my/space/resources/readline/
Usage as a Python module
- Create a readline-4.3.pkg from a folder containing the GNU Readline library sources:
pm = PackageMaker("readline-4.3", "4.3", "GNU Readline Library")
pm.build("/my/space/readline-4.3")
- As above but with additional option --RequiresReboot YES
pm = PackageMaker("readline-4.3", "4.3", "GNU Readline Library")
pm.build("/my/space/readline-4.3", RequiresReboot="YES")
- As above but with additional resources directory argument (will copy its content into /my/space/readline-4.3/pkg/Contents/Resources/)
pm = PackageMaker("readline-4.3", "4.3", "GNU Readline Library")
pm.build("/my/space/readline-4.3", "/my/space/resources/readline/")
- As above but with additional single resource file
pm = PackageMaker("readline-4.3", "4.3", "GNU Readline Library")
pm.build("/my/space/readline-4.3", "/my/space/resources/readline/")
pm.addResource("/my/space/resources/scripts/postflight")
Notes
Although the package layout is adopted from pre-10.2 versions of OS X, the Installer.app on 10.2 should have no problems in dealing with the resulting packages. For the time being this layout seems sufficient enough, so there is no point in dealing with creating packages that can be installed only by the new Installer.app!
Given that such packages have a directory "shape", they are not suited for downloading over the internet. Hence, they need to be flattened somehow into a single binary file. This could be a .tar.gz, which is possible but unusual on OS X (for reasons not described here). On OS X there is a dedicated format named "Disk Image" with extension .dmg which represents an archive that can be directly mounted into the filesystem. Creating such disk images without GUI tools is somewhat of a black art (6).
For now you should be able to run buildpkg.py even on a non-OS X system and get something similar to a package, but without the real archive (needs pax) and bom files (needs mkbom) inside! This is only for providing a chance for testing to folks without OS X.
Beware of the multi-package features of Installer.app (which are not yet supported here) that can potentially screw-up your installation and are discussed in two articles on Stepwise (4). At least for versions of OS X prior to 10.2 this seemed to be a concern.
Todo
- test pre-process and post-process scripts
- handle meta-packages (extension .mpkg)
- integrate into distutils
- use alternatives for "pax" (2)
Links
(1) Brian Hill's PackageMaker:
http://personalpages.tds.net/~brian_hill/packagemaker.html
(2) Chris Roberts's OSXPM:
http://www.osxgnu.org/
(3) BSD License:
http://opensource.org/licenses/bsd-license.php
(4) Stepwise articles:
http://www.stepwise.com/Articles/Technical/Packages/InstallerWoes.html
http://www.stepwise.com/Articles/Technical/Packages/InstallerOnX.html
(5) http://developer.apple.com/techpubs/macosx/Essentials/SystemOverview/InstallIntegrate/Installing__Application.html
http://developer.apple.com/techpubs/macosx/ReleaseNotes/PackageMaker.html
(6) Andrew Stone's notes on creating disk images:
http://www.stone.com/The_Cocoa_Files/Just_Ship_it_.html
(7) Open Source Initiative, BSD License:
http://opensource.org/licenses/bsd-license.php
Dinu C. Gherman,
gherman@europemail.com
September 2002
src
#####################################################################################################################
1#!/usr/bin/env python
2
3"""buildpkg.py -- Build OS X packages for Apple's Installer.app.
4
5This is an experimental command-line tool for building packages to be
6installed with the Mac OS X Installer.app application.
7
8Please read the file ReadMe.txt for more information!
9
10Dinu C. Gherman,
11gherman@europemail.com
12September 2002
13
14!! USE AT YOUR OWN RISK !!
15"""
16
17__version__ = 0.3
18__license__ = "FreeBSD"
19
20
21import os, sys, glob, fnmatch, shutil, string, copy, getopt
22from os.path import basename, dirname, join, islink, isdir, isfile
23
24Error = "buildpkg.Error"
25
26PKG_INFO_FIELDS = """\
27Title
28Version
29Description
30DefaultLocation
31Diskname
32DeleteWarning
33NeedsAuthorization
34DisableStop
35UseUserMask
36Application
37Relocatable
38Required
39InstallOnly
40RequiresReboot
41InstallFat\
42"""
43
44######################################################################
45# Helpers
46######################################################################
47
48# Convenience class, as suggested by /F.
49
50class GlobDirectoryWalker:
51 "A forward iterator that traverses files in a directory tree."
52
53 def __init__(self, directory, pattern="*"):
54 self.stack = [directory]
55 self.pattern = pattern
56 self.files = []
57 self.index = 0
58
59
60 def __getitem__(self, index):
61 while 1:
62 try:
63 file = self.files[self.index]
64 self.index = self.index + 1
65 except IndexError:
66 # pop next directory from stack
67 self.directory = self.stack.pop()
68 self.files = os.listdir(self.directory)
69 self.index = 0
70 else:
71 # got a filename
72 fullname = join(self.directory, file)
73 if isdir(fullname) and not islink(fullname):
74 self.stack.append(fullname)
75 if fnmatch.fnmatch(file, self.pattern):
76 return fullname
77
78
79######################################################################
80# The real thing
81######################################################################
82
83class PackageMaker:
84 """A class to generate packages for Mac OS X.
85
86 This is intended to create OS X packages (with extension .pkg)
87 containing archives of arbitrary files that the Installer.app
88 (Apple's OS X installer) will be able to handle.
89
90 As of now, PackageMaker instances need to be created with the
91 title, version and description of the package to be built.
92
93 The package is built after calling the instance method
94 build(root, resources, **options). The generated package is
95 a folder hierarchy with the top-level folder name equal to the
96 constructor's title argument plus a '.pkg' extension. This final
97 package is stored in the current folder.
98
99 The sources from the root folder will be stored in the package
100 as a compressed archive, while all files and folders from the
101 resources folder will be added to the package as they are.
102
103 Example:
104
105 With /my/space being the current directory, the following will
106 create /my/space/distutils-1.0.2.pkg/:
107
108 PM = PackageMaker
109 pm = PM("distutils-1.0.2", "1.0.2", "Python distutils.")
110 pm.build("/my/space/sources/distutils-1.0.2")
111
112 After a package is built you can still add further individual
113 resource files or folders to its Contents/Resources subfolder
114 by using the addResource(path) method:
115
116 pm.addResource("/my/space/metainfo/distutils/")
117 """
118
119 packageInfoDefaults = {
120 'Title': None,
121 'Version': None,
122 'Description': '',
123 'DefaultLocation': '/',
124 'Diskname': '(null)',
125 'DeleteWarning': '',
126 'NeedsAuthorization': 'NO',
127 'DisableStop': 'NO',
128 'UseUserMask': 'YES',
129 'Application': 'NO',
130 'Relocatable': 'YES',
131 'Required': 'NO',
132 'InstallOnly': 'NO',
133 'RequiresReboot': 'NO',
134 'InstallFat': 'NO'}
135
136
137 def __init__(self, title, version, desc):
138 "Init. with mandatory title/version/description arguments."
139
140 info = {"Title": title, "Version": version, "Description": desc}
141 self.packageInfo = copy.deepcopy(self.packageInfoDefaults)
142 self.packageInfo.update(info)
143
144 # variables set later
145 self.packageRootFolder = None
146 self.packageResourceFolder = None
147 self.sourceFolder = None
148 self.resourceFolder = None
149
150
151 def _escapeBlanks(self, s):
152 "Return a string with escaped blanks."
153
154 return s.replace(' ', '\ ')
155
156
157 def build(self, root, resources=None, **options):
158 """Create a package for some given root folder.
159
160 With no 'resources' argument set it is assumed to be the same
161 as the root directory. Option items replace the default ones
162 in the package info.
163 """
164
165 # set folder attributes
166 self.sourceFolder = root
167 if resources == None:
168 self.resourceFolder = None
169 else:
170 self.resourceFolder = resources
171
172 # replace default option settings with user ones if provided
173 fields = self. packageInfoDefaults.keys()
174 for k, v in options.items():
175 if k in fields:
176 self.packageInfo[k] = v
177 elif not k in ["OutputDir"]:
178 raise Error, "Unknown package option: %s" % k
179
180 # Check where we should leave the output. Default is current directory
181 outputdir = options.get("OutputDir", os.getcwd())
182 packageName = self.packageInfo["Title"]
183 self.packageRootFolder = os.path.join(outputdir, packageName + ".pkg")
184
185 # do what needs to be done
186 self._makeFolders()
187 self._addInfo()
188 self._addBom()
189 self._addArchive()
190 self._addResources()
191 self._addSizes()
192
193
194 def addResource(self, path):
195 "Add arbitrary file or folder to the package resource folder."
196
197 # Folder basenames become subfolders of Contents/Resources.
198 # This method is made public for those who wknow what they do!
199
200 prf = self.packageResourceFolder
201 if isfile(path) and not isdir(path):
202 shutil.copy(path, prf)
203 elif isdir(path):
204 path = self._escapeBlanks(path)
205 prf = self._escapeBlanks(prf)
206 os.system("cp -r %s %s" % (path, prf))
207
208
209 def _makeFolders(self):
210 "Create package folder structure."
211
212 # Not sure if the package name should contain the version or not
213 # packageName = "%s-%s" % (self.packageInfo["Title"],
214 # self.packageInfo["Version"]) # ??
215
216 contFolder = join(self.packageRootFolder, "Contents")
217 self.packageResourceFolder = join(contFolder, "Resources")
218 os.mkdir(self.packageRootFolder)
219 os.mkdir(contFolder)
220 os.mkdir(self.packageResourceFolder)
221
222
223 def _addInfo(self):
224 "Write .info file containing installing options."
225
226 # Not sure if options in PKG_INFO_FIELDS are complete
227
228 info = ""
229 for f in string.split(PKG_INFO_FIELDS, "\n"):
230 info = info + "%s %%(%s)s\n" % (f, f)
231 info = info % self.packageInfo
232 base = self.packageInfo["Title"] + ".info"
233 path = join(self.packageResourceFolder, base)
234 f = open(path, "w")
235 f.write(info)
236
237
238 def _addBom(self):
239 "Write .bom file containing 'Bill of Materials'."
240
241 # Currently ignores if the 'mkbom' tool is not available.
242
243 try:
244 base = self.packageInfo["Title"] + ".bom"
245 bomPath = join(self.packageResourceFolder, base)
246 bomPath = self._escapeBlanks(bomPath)
247 sourceFolder = self._escapeBlanks(self.sourceFolder)
248 cmd = "mkbom %s %s" % (sourceFolder, bomPath)
249 res = os.system(cmd)
250 except:
251 pass
252
253
254 def _addArchive(self):
255 "Write .pax.gz file, a compressed archive using pax/gzip."
256
257 # Currently ignores if the 'pax' tool is not available.
258
259 cwd = os.getcwd()
260
261 # create archive
262 os.chdir(self.sourceFolder)
263 base = basename(self.packageInfo["Title"]) + ".pax"
264 self.archPath = join(self.packageResourceFolder, base)
265 archPath = self._escapeBlanks(self.archPath)
266 cmd = "pax -w -f %s %s" % (archPath, ".")
267 res = os.system(cmd)
268
269 # compress archive
270 cmd = "gzip %s" % archPath
271 res = os.system(cmd)
272 os.chdir(cwd)
273
274
275 def _addResources(self):
276 "Add all files and folders inside a resources folder to the package."
277
278 # This folder normally contains Welcome/ReadMe/License files,
279 # .lproj folders and scripts.
280
281 if not self.resourceFolder:
282 return
283
284 files = glob.glob("%s/*" % self.resourceFolder)
285 for f in files:
286 self.addResource(f)
287
288
289 def _addSizes(self):
290 "Write .sizes file with info about number and size of files."
291
292 # Not sure if this is correct, but 'installedSize' and
293 # 'zippedSize' are now in Bytes. Maybe blocks are needed?
294 # Well, Installer.app doesn't seem to care anyway, saying
295 # the installation needs 100+ MB
296
297 numFiles = 0
298 installedSize = 0
299 zippedSize = 0
300
301 files = GlobDirectoryWalker(self.sourceFolder)
302 for f in files:
303 numFiles = numFiles + 1
304 installedSize = installedSize + os.lstat(f)[6]
305
306 try:
307 zippedSize = os.stat(self.archPath+ ".gz")[6]
308 except OSError: # ignore error
309 pass
310 base = self.packageInfo["Title"] + ".sizes"
311 f = open(join(self.packageResourceFolder, base), "w")
312 format = "NumFiles %d\nInstalledSize %d\nCompressedSize %d\n"
313 f.write(format % (numFiles, installedSize, zippedSize))
314
315
316# Shortcut function interface
317
318def buildPackage(*args, **options):
319 "A shortcut function for building a package."
320
321 o = options
322 title, version, desc = o["Title"], o["Version"], o["Description"]
323 pm = PackageMaker(title, version, desc)
324 apply(pm.build, list(args), options)
325
326 return pm
327
328
329######################################################################
330# Command-line interface
331######################################################################
332
333def printUsage():
334 "Print usage message."
335
336 format = "Usage: %s <opts1> [<opts2>] <root> [<resources>]"
337 print format % basename(sys.argv[0])
338 print
339 print " with arguments:"
340 print " (mandatory) root: the package root folder"
341 print " (optional) resources: the package resources folder"
342 print
343 print " and options:"
344 print " (mandatory) opts1:"
345 mandatoryKeys = string.split("Title Version Description", " ")
346 for k in mandatoryKeys:
347 print " --%s" % k
348 print " (optional) opts2: (with default values)"
349
350 pmDefaults = PackageMaker.packageInfoDefaults
351 optionalKeys = pmDefaults.keys()
352 for k in mandatoryKeys:
353 optionalKeys.remove(k)
354 optionalKeys.sort()
355 maxKeyLen = max(map(len, optionalKeys))
356 for k in optionalKeys:
357 format = " --%%s:%s %%s"
358 format = format % (" " * (maxKeyLen-len(k)))
359 print format % (k, repr(pmDefaults[k]))
360
361
362def main():
363 "Command-line interface."
364
365 shortOpts = ""
366 keys = PackageMaker.packageInfoDefaults.keys()
367 longOpts = map(lambda k: k+"=", keys)
368
369 try:
370 opts, args = getopt.getopt(sys.argv[1:], shortOpts, longOpts)
371 except getopt.GetoptError, details:
372 print details
373 printUsage()
374 return
375
376 optsDict = {}
377 for k, v in opts:
378 optsDict[k[2:]] = v
379
380 ok = optsDict.keys()
381 if not (1 <= len(args) <= 2):
382 print "No argument given!"
383 elif not ("Title" in ok and \
384 "Version" in ok and \
385 "Description" in ok):
386 print "Missing mandatory option!"
387 else:
388 pm = apply(buildPackage, args, optsDict)
389 return
390
391 printUsage()
392
393 # sample use:
394 # buildpkg.py --Title=distutils \
395 # --Version=1.0.2 \
396 # --Description="Python distutils package." \
397 # /Users/dinu/Desktop/distutils
398
399
400if __name__ == "__main__":
401 main()
402
#################################################################################################################
自述
buildpkg.py - Python的工具来构建一个苹果的installer.app安装OS X软件包。
目的
这是一个Python的工具包的建设要与installer.app安装Mac OS X的应用程序安装。这是许多灵感来自苹果的图形用户界面称为PackageMaker.app工具,它是OS X的开发商/开发/应用安装工具的一部分。还有其他一些免费的GUI工具做同样的事(1),(2)。这个工具没有GUI这是一个特色,而不是一个错误。
版本
当前版本是0.3。
许可证
此版本目前的授权是“BSD许可证”由开放源码促进会(7)中所述。
关于苹果的installer.app安装
苹果公司已经确定了它自己的格式的软件程序包将在OS X系统安装。源于这种格式最初是从马赫/ NeXTSTEP的操作系统OS X是其中一个直接的继任者。这种一包的形状基本上是与高层有一个嵌套目录的扩展集。封装(或。的MPKG)。它包含一个存档与“百富”,再加上进一步说明包内容的文件,以及其他可选脚本在安装过程中运行压缩。不幸的是,苹果并没有全面记录其所有的功能或宣布安装包中的布局变化。
特点buildpkg.py
由buildpkg.py的重要工作进行名为<PACKAGE>一个新的包是:
- 创建一个包目录<PACKAGE>封装/加上其整个布局(子目录)。
- 添加文件<PACKAGE>封装/ <PACKAGE>信息包含安装选项。。
- 增加了“材料清单”文件<PACKAGE>封装/ <PACKAGE>的BOM(用“mkbom”)。。
- 添加为<PACKAGE>封装/ <PACKAGE>源根目录pax.gz。。
- 添加可选的资源<PACKAGE> .pkg /目录/资源
- 添加文件<PACKAGE>封装/ <PACKAGE>大小显示已安装的包的总大小。。
其中可选的资源文件有欢迎,自述文件和许可证文件(无论是在的。txt,。RTF格式。rtfd /或。HTML格式)在安装过程中显示。这些也可以包内的定位,如English.lproj /或German.lproj /)。其他资源将主要是安装脚本(比如预检,<PACKAGE> {前,后} - 。{升级,安装},飞行后,或许其他人也如此)由安装在适当的时候调用。
buildpkg.py不自作聪明足够的过滤器只从你指定的资源相关的文件。它简单地复制到它们打包。
命令行用法
该buildpkg.py脚本的用途是两个,作为一个命令行工具,作为一个Python模块,它可以导入其他Python程序(用“的distutils”是最明显的候选人的Python包)。
- 呼叫不带任何选项/参数的程序
达尔文%的Python buildpkg.py
没有参数给出!
用法:buildpkg.py <opts1> [<opts2>] <根目录[<resources>]
带参数:
(强制)的根:包根文件夹
(可选)资源:软件包资源文件夹
和选项:
(强制)opts1:
- 标题
- 版本
- 描述
(可选)opts2:(使用默认值)
- 应用:'没有'
- DefaultLocation:'/'
- DeleteWarning:''
- DisableStop:'没有'
- Diskname:'(空)'
- InstallFat:'没有'
- InstallOnly:'没有'
- NeedsAuthorization:'没有'
- 重新定位:'是'
- 必需的:'没有'
- RequiresReboot:'没有'
- UseUserMask:'是'
- 呼叫,只有强制性的选项和参数的程序
达尔文%的Python buildpkg.py - 标题= readline的- 4.3 - 版本= 4.3 \
- 描述=“GNU的readline库”/ my/space/readline-4.3
- 同上,但有更多的选择 - RequiresReboot是的
达尔文%的Python buildpkg.py - 标题= readline的- 4.3 - 版本= 4.3 \
- 描述=“GNU的readline库” - RequiresReboot是\
/ my/space/readline-4.3
- 同上,但更多的资源目录参数(将复制到/ my/space/readline-4.3/pkg/Contents/Resources其内容/)
达尔文%的Python buildpkg.py - 标题= readline的- 4.3 - 版本= 4.3 \
- 描述=“GNU的readline库” - RequiresReboot是\
/ my/space/readline-4.3 /我/空间/资源/ readline的/
作为一个Python模块的使用情况
- 创建的ReadLine从一个包含GNU readline库源文件夹4.3.pkg:
下午= PackageMaker(“readline的- 4.3”,“4.3”,“GNU的readline库”)
pm.build(“/ my/space/readline-4.3”)
- 同上,但有更多的选择 - RequiresReboot是的
下午= PackageMaker(“readline的- 4.3”,“4.3”,“GNU的readline库”)
pm.build(“/ my/space/readline-4.3”,RequiresReboot =“是”)
- 同上,但更多的资源目录参数(将复制到/ my/space/readline-4.3/pkg/Contents/Resources其内容/)
下午= PackageMaker(“readline的- 4.3”,“4.3”,“GNU的readline库”)
pm.build(“/ my/space/readline-4.3”,“/我/空间/资源/ readline的/”)
- 同上,但与其他单一的资源文件
下午= PackageMaker(“readline的- 4.3”,“4.3”,“GNU的readline库”)
pm.build(“/ my/space/readline-4.3”,“/我/空间/资源/ readline的/”)
pm.addResource(“/我/空间/资源/脚本/飞行后”)
注释
虽然包布局从前期的OS X版本10.2通过,应该在10.2 installer.app安装在与由此产生的包处理没有问题。就目前这个时间似乎足以布局,所以没有与创造,可以安装新的installer.app安装只包处理点!
由于这些包有一个目录“形”,他们是不适合在互联网上下载。因此,他们需要缩减到一个单一的二进制文件不知。这可能是一个。tar.gz的,这是可能的,但在OS X上不寻常的(这里没有说明原因)。在OS X上有一个专门的格式,扩展名为“磁盘图像”。伤害它代表一个可直接安装到文件系统归档。没有GUI工具,例如创建磁盘映像是有点黑色艺术(6)。
现在你应该能够运行buildpkg.py即使在非OS X系统,并得到类似的一包,但没有真正的存档(需求人数)和BOM文件(需要mkbom)里面!这只是提供OS X的测试没有机会到民间的
慎防installer.app安装多包的功能(这是目前还不支持在这里),可以潜在螺杆式安装,并在两个逐步(4)文章中讨论。在对OS X版本10.2之前至少这似乎是一个问题。
托多
- 测试预处理和后处理的脚本
- 处理元包(扩展名的MPKG。)
- 融入的distutils
- 使用“百富”(2)替代品
链接
(1)布莱恩希尔的PackageMaker:
http://personalpages.tds.net/〜brian_hill / packagemaker.html
(2)的克里斯罗伯茨OSXPM:
http://www.osxgnu.org/
(3)的BSD许可:
http://opensource.org/licenses/bsd-license.php
(4)逐步文章:
http://www.stepwise.com/Articles/Technical/Packages/InstallerWoes.html
http://www.stepwise.com/Articles/Technical/Packages/InstallerOnX.html
(5)http://developer.apple.com/techpubs/macosx/Essentials/SystemOverview/InstallIntegrate/Installing__Application.html
http://developer.apple.com/techpubs/macosx/ReleaseNotes/PackageMaker.html
(6)创建磁盘映像安德鲁斯通的注意事项:
http://www.stone.com/The_Cocoa_Files/Just_Ship_it_.html
(7)开源倡议,BSD许可证:
http://opensource.org/licenses/bsd-license.php
Dinu三盖尔曼,
gherman@europemail.com
2002年9月