Back to index

python3.2  3.2.2
Public Member Functions | Public Attributes | Static Public Attributes | Private Member Functions
bundlebuilder.AppBuilder Class Reference
Inheritance diagram for bundlebuilder.AppBuilder:
Inheritance graph
[legend]
Collaboration diagram for bundlebuilder.AppBuilder:
Collaboration graph
[legend]

List of all members.

Public Member Functions

def setup
def preProcess
def postProcess
def addPythonFramework
def addPythonModules
def stripBinaries
def findDependencies
def reportMissing
def report
def build
def message

Public Attributes

 execdir
 name
 symlink_exec
 execpath
 bundlepath

Static Public Attributes

string type = "APPL"
string platform = "MacOS"
 mainprogram = None
 executable = None
 nibname = None
 iconfile = None
int symlink_exec = 0
int standalone = 0
int semi_standalone = 0
 python = None
int argv_emulation = 0
list excludeModules = []
list includeModules = []
list includePackages = []
int strip = 0
list pymodules = []
list missingModules = []
list maybeMissingModules = []
tuple plist
 creator = None
 bundle_id = None
list resources = []
list files = []
list libs = []
string builddir = "build"
int symlink = 0
int verbosity = 1
string destroot = ""

Private Member Functions

def _getSiteCode

Detailed Description

Definition at line 348 of file bundlebuilder.py.


Member Function Documentation

def bundlebuilder.AppBuilder._getSiteCode (   self) [private]

Definition at line 551 of file bundlebuilder.py.

00551 
00552     def _getSiteCode(self):
00553         return compile(SITE_PY % {"semi_standalone": self.semi_standalone},
00554                      "<-bundlebuilder.py->", "exec")

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 530 of file bundlebuilder.py.

00530 
00531     def addPythonFramework(self):
00532         # If we're building a standalone app with Python.framework,
00533         # include a minimal subset of Python.framework, *unless*
00534         # Python.framework was specified manually in self.libs.
00535         for lib in self.libs:
00536             if os.path.basename(lib) == "Python.framework":
00537                 # a Python.framework was specified as a library
00538                 return
00539 
00540         frameworkpath = sys.exec_prefix[:sys.exec_prefix.find(
00541             "Python.framework") + len("Python.framework")]
00542 
00543         version = sys.version[:3]
00544         frameworkpath = pathjoin(frameworkpath, "Versions", version)
00545         destbase = pathjoin("Contents", "Frameworks", "Python.framework",
00546                             "Versions", version)
00547         for item in PYTHONFRAMEWORKGOODIES:
00548             src = pathjoin(frameworkpath, item)
00549             dst = pathjoin(destbase, item)
00550             self.files.append((src, dst))

Here is the call graph for this function:

Definition at line 555 of file bundlebuilder.py.

00555 
00556     def addPythonModules(self):
00557         self.message("Adding Python modules", 1)
00558 
00559         if USE_ZIPIMPORT:
00560             # Create a zip file containing all modules as pyc.
00561             import zipfile
00562             relpath = pathjoin("Contents", "Resources", ZIP_ARCHIVE)
00563             abspath = pathjoin(self.bundlepath, relpath)
00564             zf = zipfile.ZipFile(abspath, "w", zipfile.ZIP_DEFLATED)
00565             for name, code, ispkg in self.pymodules:
00566                 self.message("Adding Python module %s" % name, 2)
00567                 path, pyc = getPycData(name, code, ispkg)
00568                 zf.writestr(path, pyc)
00569             zf.close()
00570             # add site.pyc
00571             sitepath = pathjoin(self.bundlepath, "Contents", "Resources",
00572                     "site" + PYC_EXT)
00573             writePyc(self._getSiteCode(), sitepath)
00574         else:
00575             # Create individual .pyc files.
00576             for name, code, ispkg in self.pymodules:
00577                 if ispkg:
00578                     name += ".__init__"
00579                 path = name.split(".")
00580                 path = pathjoin("Contents", "Resources", *path) + PYC_EXT
00581 
00582                 if ispkg:
00583                     self.message("Adding Python package %s" % path, 2)
00584                 else:
00585                     self.message("Adding Python module %s" % path, 2)
00586 
00587                 abspath = pathjoin(self.bundlepath, path)
00588                 makedirs(os.path.dirname(abspath))
00589                 writePyc(code, abspath)

Here is the call graph for this function:

Here is the caller graph for this function:

def bundlebuilder.BundleBuilder.build (   self) [inherited]
Build the bundle.

Definition at line 140 of file bundlebuilder.py.

00140 
00141     def build(self):
00142         """Build the bundle."""
00143         builddir = self.builddir
00144         if builddir and not os.path.exists(builddir):
00145             os.mkdir(builddir)
00146         self.message("Building %s" % repr(self.bundlepath), 1)
00147         if os.path.exists(self.bundlepath):
00148             shutil.rmtree(self.bundlepath)
00149         if os.path.exists(self.bundlepath + '~'):
00150             shutil.rmtree(self.bundlepath + '~')
00151         bp = self.bundlepath
00152 
00153         # Create the app bundle in a temporary location and then
00154         # rename the completed bundle. This way the Finder will
00155         # never see an incomplete bundle (where it might pick up
00156         # and cache the wrong meta data)
00157         self.bundlepath = bp + '~'
00158         try:
00159             os.mkdir(self.bundlepath)
00160             self.preProcess()
00161             self._copyFiles()
00162             self._addMetaFiles()
00163             self.postProcess()
00164             os.rename(self.bundlepath, bp)
00165         finally:
00166             self.bundlepath = bp
00167         self.message("Done.", 1)

Here is the call graph for this function:

Definition at line 620 of file bundlebuilder.py.

00620 
00621     def findDependencies(self):
00622         self.message("Finding module dependencies", 1)
00623         import modulefinder
00624         mf = modulefinder.ModuleFinder(excludes=self.excludeModules)
00625         if USE_ZIPIMPORT:
00626             # zipimport imports zlib, must add it manually
00627             mf.import_hook("zlib")
00628         # manually add our own site.py
00629         site = mf.add_module("site")
00630         site.__code__ = self._getSiteCode()
00631         mf.scan_code(site.__code__, site)
00632 
00633         # warnings.py gets imported implicitly from C
00634         mf.import_hook("warnings")
00635 
00636         includeModules = self.includeModules[:]
00637         for name in self.includePackages:
00638             includeModules.extend(list(findPackageContents(name).keys()))
00639         for name in includeModules:
00640             try:
00641                 mf.import_hook(name)
00642             except ImportError:
00643                 self.missingModules.append(name)
00644 
00645         mf.run_script(self.mainprogram)
00646         modules = list(mf.modules.items())
00647         modules.sort()
00648         for name, mod in modules:
00649             path = mod.__file__
00650             if path and self.semi_standalone:
00651                 # skip the standard library
00652                 if path.startswith(LIB) and not path.startswith(SITE_PACKAGES):
00653                     continue
00654             if path and mod.__code__ is None:
00655                 # C extension
00656                 filename = os.path.basename(path)
00657                 pathitems = name.split(".")[:-1] + [filename]
00658                 dstpath = pathjoin(*pathitems)
00659                 if USE_ZIPIMPORT:
00660                     if name != "zlib":
00661                         # neatly pack all extension modules in a subdirectory,
00662                         # except zlib, since it's necessary for bootstrapping.
00663                         dstpath = pathjoin("ExtensionModules", dstpath)
00664                     # Python modules are stored in a Zip archive, but put
00665                     # extensions in Contents/Resources/. Add a tiny "loader"
00666                     # program in the Zip archive. Due to Thomas Heller.
00667                     source = EXT_LOADER % {"name": name, "filename": dstpath}
00668                     code = compile(source, "<dynloader for %s>" % name, "exec")
00669                     mod.__code__ = code
00670                 self.files.append((path, pathjoin("Contents", "Resources", dstpath)))
00671             if mod.__code__ is not None:
00672                 ispkg = mod.__path__ is not None
00673                 if not USE_ZIPIMPORT or name != "site":
00674                     # Our site.py is doing the bootstrapping, so we must
00675                     # include a real .pyc file if USE_ZIPIMPORT is True.
00676                     self.pymodules.append((name, mod.__code__, ispkg))
00677 
00678         if hasattr(mf, "any_missing_maybe"):
00679             missing, maybe = mf.any_missing_maybe()
00680         else:
00681             missing = mf.any_missing()
00682             maybe = []
00683         self.missingModules.extend(missing)
00684         self.maybeMissingModules.extend(maybe)

Here is the call graph for this function:

def bundlebuilder.BundleBuilder.message (   self,
  msg,
  level = 0 
) [inherited]

Definition at line 217 of file bundlebuilder.py.

00217 
00218     def message(self, msg, level=0):
00219         if level <= self.verbosity:
00220             indent = ""
00221             if level > 1:
00222                 indent = (level - 1) * "  "
00223             sys.stderr.write(indent + msg + "\n")

Here is the caller graph for this function:

Hook for subclasses.

Reimplemented from bundlebuilder.BundleBuilder.

Definition at line 514 of file bundlebuilder.py.

00514 
00515     def postProcess(self):
00516         if self.standalone or self.semi_standalone:
00517             self.addPythonModules()
00518         if self.strip and not self.symlink:
00519             self.stripBinaries()
00520 
00521         if self.symlink_exec and self.executable:
00522             self.message("Symlinking executable %s to %s" % (self.executable,
00523                     self.execpath), 2)
00524             dst = pathjoin(self.bundlepath, self.execpath)
00525             makedirs(os.path.dirname(dst))
00526             os.symlink(os.path.abspath(self.executable), dst)
00527 
00528         if self.missingModules or self.maybeMissingModules:
00529             self.reportMissing()

Here is the call graph for this function:

Hook for subclasses.

Reimplemented from bundlebuilder.BundleBuilder.

Definition at line 455 of file bundlebuilder.py.

00455 
00456     def preProcess(self):
00457         resdir = "Contents/Resources"
00458         if self.executable is not None:
00459             if self.mainprogram is None:
00460                 execname = self.name
00461             else:
00462                 execname = os.path.basename(self.executable)
00463             execpath = pathjoin(self.execdir, execname)
00464             if not self.symlink_exec:
00465                 self.files.append((self.destroot + self.executable, execpath))
00466             self.execpath = execpath
00467 
00468         if self.mainprogram is not None:
00469             mainprogram = os.path.basename(self.mainprogram)
00470             self.files.append((self.mainprogram, pathjoin(resdir, mainprogram)))
00471             if self.argv_emulation:
00472                 # Change the main program, and create the helper main program (which
00473                 # does argv collection and then calls the real main).
00474                 # Also update the included modules (if we're creating a standalone
00475                 # program) and the plist
00476                 realmainprogram = mainprogram
00477                 mainprogram = '__argvemulator_' + mainprogram
00478                 resdirpath = pathjoin(self.bundlepath, resdir)
00479                 mainprogrampath = pathjoin(resdirpath, mainprogram)
00480                 makedirs(resdirpath)
00481                 open(mainprogrampath, "w").write(ARGV_EMULATOR % locals())
00482                 if self.standalone or self.semi_standalone:
00483                     self.includeModules.append("argvemulator")
00484                     self.includeModules.append("os")
00485                 if "CFBundleDocumentTypes" not in self.plist:
00486                     self.plist["CFBundleDocumentTypes"] = [
00487                         { "CFBundleTypeOSTypes" : [
00488                             "****",
00489                             "fold",
00490                             "disk"],
00491                           "CFBundleTypeRole": "Viewer"}]
00492             # Write bootstrap script
00493             executable = os.path.basename(self.executable)
00494             execdir = pathjoin(self.bundlepath, self.execdir)
00495             bootstrappath = pathjoin(execdir, self.name)
00496             makedirs(execdir)
00497             if self.standalone or self.semi_standalone:
00498                 # XXX we're screwed when the end user has deleted
00499                 # /usr/bin/python
00500                 hashbang = "/usr/bin/python"
00501             elif self.python:
00502                 hashbang = self.python
00503             else:
00504                 hashbang = os.path.realpath(sys.executable)
00505             standalone = self.standalone
00506             semi_standalone = self.semi_standalone
00507             open(bootstrappath, "w").write(BOOTSTRAP_SCRIPT % locals())
00508             os.chmod(bootstrappath, 0o775)
00509 
00510         if self.iconfile is not None:
00511             iconbase = os.path.basename(self.iconfile)
00512             self.plist.CFBundleIconFile = iconbase
00513             self.files.append((self.iconfile, pathjoin(resdir, iconbase)))

Here is the call graph for this function:

Reimplemented from bundlebuilder.BundleBuilder.

Definition at line 709 of file bundlebuilder.py.

00709 
00710     def report(self):
00711         # XXX something decent
00712         import pprint
00713         pprint.pprint(self.__dict__)
00714         if self.standalone or self.semi_standalone:
00715             self.reportMissing()
00716 
00717 #
00718 # Utilities.
00719 #

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 685 of file bundlebuilder.py.

00685 
00686     def reportMissing(self):
00687         missing = [name for name in self.missingModules
00688                 if name not in MAYMISS_MODULES]
00689         if self.maybeMissingModules:
00690             maybe = self.maybeMissingModules
00691         else:
00692             maybe = [name for name in missing if "." in name]
00693             missing = [name for name in missing if "." not in name]
00694         missing.sort()
00695         maybe.sort()
00696         if maybe:
00697             self.message("Warning: couldn't find the following submodules:", 1)
00698             self.message("    (Note that these could be false alarms -- "
00699                          "it's not always", 1)
00700             self.message("    possible to distinguish between \"from package "
00701                          "import submodule\" ", 1)
00702             self.message("    and \"from package import name\")", 1)
00703             for name in maybe:
00704                 self.message("  ? " + name, 1)
00705         if missing:
00706             self.message("Warning: couldn't find the following modules:", 1)
00707             for name in missing:
00708                 self.message("  ? " + name, 1)

Here is the call graph for this function:

Here is the caller graph for this function:

Reimplemented from bundlebuilder.BundleBuilder.

Definition at line 412 of file bundlebuilder.py.

00412 
00413     def setup(self):
00414         if ((self.standalone or self.semi_standalone)
00415             and self.mainprogram is None):
00416             raise BundleBuilderError("must specify 'mainprogram' when "
00417                     "building a standalone application.")
00418         if self.mainprogram is None and self.executable is None:
00419             raise BundleBuilderError("must specify either or both of "
00420                     "'executable' and 'mainprogram'")
00421 
00422         self.execdir = pathjoin("Contents", self.platform)
00423 
00424         if self.name is not None:
00425             pass
00426         elif self.mainprogram is not None:
00427             self.name = os.path.splitext(os.path.basename(self.mainprogram))[0]
00428         elif executable is not None:
00429             self.name = os.path.splitext(os.path.basename(self.executable))[0]
00430         if self.name[-4:] != ".app":
00431             self.name += ".app"
00432 
00433         if self.executable is None:
00434             if not self.standalone and not isFramework():
00435                 self.symlink_exec = 1
00436             if self.python:
00437                 self.executable = self.python
00438             else:
00439                 self.executable = sys.executable
00440 
00441         if self.nibname:
00442             self.plist.NSMainNibFile = self.nibname
00443             if not hasattr(self.plist, "NSPrincipalClass"):
00444                 self.plist.NSPrincipalClass = "NSApplication"
00445 
00446         if self.standalone and isFramework():
00447             self.addPythonFramework()
00448 
00449         BundleBuilder.setup(self)
00450 
00451         self.plist.CFBundleExecutable = self.name
00452 
00453         if self.standalone or self.semi_standalone:
00454             self.findDependencies()

Definition at line 590 of file bundlebuilder.py.

00590 
00591     def stripBinaries(self):
00592         if not os.path.exists(STRIP_EXEC):
00593             self.message("Error: can't strip binaries: no strip program at "
00594                 "%s" % STRIP_EXEC, 0)
00595         else:
00596             import stat
00597             self.message("Stripping binaries", 1)
00598             def walk(top):
00599                 for name in os.listdir(top):
00600                     path = pathjoin(top, name)
00601                     if os.path.islink(path):
00602                         continue
00603                     if os.path.isdir(path):
00604                         walk(path)
00605                     else:
00606                         mod = os.stat(path)[stat.ST_MODE]
00607                         if not (mod & 0o100):
00608                             continue
00609                         relpath = path[len(self.bundlepath):]
00610                         self.message("Stripping %s" % relpath, 2)
00611                         inf, outf = os.popen4("%s -S \"%s\"" %
00612                                               (STRIP_EXEC, path))
00613                         output = outf.read().strip()
00614                         if output:
00615                             # usually not a real problem, like when we're
00616                             # trying to strip a script
00617                             self.message("Problem stripping %s:" % relpath, 3)
00618                             self.message(output, 3)
00619             walk(self.bundlepath)

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Definition at line 389 of file bundlebuilder.py.

string bundlebuilder.BundleBuilder.builddir = "build" [static, inherited]

Definition at line 105 of file bundlebuilder.py.

bundlebuilder.BundleBuilder.bundle_id = None [static, inherited]

Definition at line 91 of file bundlebuilder.py.

Definition at line 124 of file bundlebuilder.py.

bundlebuilder.BundleBuilder.creator = None [static, inherited]

Definition at line 88 of file bundlebuilder.py.

string bundlebuilder.BundleBuilder.destroot = "" [static, inherited]

Definition at line 115 of file bundlebuilder.py.

Definition at line 394 of file bundlebuilder.py.

Definition at line 421 of file bundlebuilder.py.

Definition at line 465 of file bundlebuilder.py.

Definition at line 365 of file bundlebuilder.py.

list bundlebuilder.BundleBuilder.files = [] [static, inherited]

Definition at line 98 of file bundlebuilder.py.

Definition at line 373 of file bundlebuilder.py.

Definition at line 397 of file bundlebuilder.py.

Definition at line 400 of file bundlebuilder.py.

list bundlebuilder.BundleBuilder.libs = [] [static, inherited]

Definition at line 102 of file bundlebuilder.py.

Definition at line 359 of file bundlebuilder.py.

Definition at line 410 of file bundlebuilder.py.

Definition at line 409 of file bundlebuilder.py.

Reimplemented from bundlebuilder.BundleBuilder.

Definition at line 426 of file bundlebuilder.py.

Definition at line 369 of file bundlebuilder.py.

Definition at line 354 of file bundlebuilder.py.

tuple bundlebuilder.BundleBuilder.plist [static, inherited]
Initial value:
Plist(CFBundleDevelopmentRegion = "English",
                  CFBundleInfoDictionaryVersion = "6.0")

Definition at line 82 of file bundlebuilder.py.

Definition at line 406 of file bundlebuilder.py.

Definition at line 385 of file bundlebuilder.py.

list bundlebuilder.BundleBuilder.resources = [] [static, inherited]

Definition at line 94 of file bundlebuilder.py.

Definition at line 382 of file bundlebuilder.py.

Definition at line 379 of file bundlebuilder.py.

Definition at line 403 of file bundlebuilder.py.

int bundlebuilder.BundleBuilder.symlink = 0 [static, inherited]

Definition at line 109 of file bundlebuilder.py.

Definition at line 376 of file bundlebuilder.py.

Definition at line 434 of file bundlebuilder.py.

Reimplemented from bundlebuilder.BundleBuilder.

Definition at line 351 of file bundlebuilder.py.

int bundlebuilder.BundleBuilder.verbosity = 1 [static, inherited]

Definition at line 112 of file bundlebuilder.py.


The documentation for this class was generated from the following file: