diff --git a/.pydevproject b/.pydevproject
index 416319d077..fba36e6fb7 100644
--- a/.pydevproject
+++ b/.pydevproject
@@ -5,9 +5,5 @@
python 2.5
/calibre/src
-/calibre/devices
-/calibre/libprs500.devices.prs500
-/calibre/prs500
-/calibre/gui2
diff --git a/installer/cx_Freeze/HISTORY.txt b/installer/cx_Freeze/HISTORY.txt
new file mode 100644
index 0000000000..acf9ad0dfe
--- /dev/null
+++ b/installer/cx_Freeze/HISTORY.txt
@@ -0,0 +1,244 @@
+Changes from 4.0 to 4.0.1
+ 1) Added support for Python 2.6. On Windows a manifest file is now required
+ because of the switch to using the new Microsoft C runtime.
+ 2) Ensure that hooks are run for builtin modules.
+
+Changes from 4.0b1 to 4.0
+ 1) Added support for copying files to the target directory.
+ 2) Added support for a hook that runs when a module is missing.
+ 3) Added support for binary path includes as well as excludes; use sequences
+ rather than dictionaries as a more convenient API; exclude the standard
+ locations for 32-bit and 64-bit libaries in multi-architecture systems.
+ 4) Added support for searching zip files (egg files) for modules.
+ 5) Added support for handling system exit exceptions similarly to what Python
+ does itself as requested by Sylvain.
+ 6) Added code to wait for threads to shut down like the normal Python
+ interpreter does. Thanks to Mariano Disanzo for discovering this
+ discrepancy.
+ 7) Hooks added or modified based on feedback from many people.
+ 8) Don't include the version name in the display name of the MSI.
+ 9) Use the OS dependent path normalization routines rather than simply use the
+ lowercase value as on Unix case is important; thanks to Artie Eoff for
+ pointing this out.
+10) Include a version attribute in the cx_Freeze package and display it in the
+ output for the --version option to the script.
+11) Include build instructions as requested by Norbert Sebok.
+12) Add support for copying files when modules are included which require data
+ files to operate properly; add support for copying the necessary files for
+ the Tkinter and matplotlib modules.
+13) Handle deferred imports recursively as needed; ensure that from lists do
+ not automatically indicate that they are part of the module or the deferred
+ import processing doesn't actually work!
+14) Handle the situation where a module imports everything from a package and
+ the __all__ variable has been defined but the package has not actually
+ imported everything in the __all__ variable during initialization.
+15) Modified license text to more closely match the Python Software Foundation
+ license as was intended.
+16) Added sample script for freezing an application using matplotlib.
+17) Renamed freeze to cxfreeze to avoid conflict with another package that uses
+ that executable as requested by Siegfried Gevatter.
+
+Changes from 3.0.3 to 4.0b1
+ 1) Added support for placing modules in library.zip or in a separate zip file
+ for each executable that is produced.
+ 2) Added support for copying binary dependent files (DLLs and shared
+ libraries)
+ 3) Added support for including all submodules in a package
+ 4) Added support for including icons in Windows executables
+ 5) Added support for constants module which can be used for determining
+ certain build constants at runtime
+ 6) Added support for relative imports available in Python 2.5 and up
+ 7) Added support for building Windows installers (Python 2.5 and up) and
+ RPM packages
+ 8) Added support for distutils configuration scripts
+ 9) Added support for hooks which can force inclusion or exclusion of modules
+ when certain modules are included
+10) Added documentation and samples
+11) Added setup.py for building the cx_Freeze package instead of a script
+ used to build only the frozen bases
+12) FreezePython renamed to a script called freeze in the Python distribution
+13) On Linux and other platforms that support it set LD_RUN_PATH to include
+ the directory in which the executable is located
+
+Changes from 3.0.2 to 3.0.3
+ 1) In Common.c, used MAXPATHLEN defined in the Python OS independent include
+ file rather than the PATH_MAX define which is OS dependent and is not
+ available on IRIX as noted by Andrew Jones.
+ 2) In the initscript ConsoleSetLibPath.py, added lines from initscript
+ Console.py that should have been there since the only difference between
+ that script and this one is the automatic re-execution of the executable.
+ 3) Added an explicit "import encodings" to the initscripts in order to handle
+ Unicode encodings a little better. Thanks to Ralf Schmitt for pointing out
+ the problem and its solution.
+ 4) Generated a meaningful name for the extension loader script so that it is
+ clear which particular extension module is being loaded when an exception
+ is being raised.
+ 5) In MakeFrozenBases.py, use distutils to figure out a few more
+ platform-dependent linker flags as suggested by Ralf Schmitt.
+
+Changes from 3.0.1 to 3.0.2
+ 1) Add support for compressing the byte code in the zip files that are
+ produced.
+ 2) Add better support for the win32com package as requested by Barry Scott.
+ 3) Prevent deletion of target file if it happens to be identical to the
+ source file.
+ 4) Include additional flags for local modifications to a Python build as
+ suggested by Benjamin Rutt.
+ 5) Expanded instructions for building cx_Freeze from source based on a
+ suggestion from Gregg Lind.
+ 6) Fix typo in help string.
+
+Changes from 3.0 to 3.0.1
+ 1) Added option --default-path which is used to specify the path used when
+ finding modules. This is particularly useful when performing cross
+ compilations (such as for building a frozen executable for Windows CE).
+ 2) Added option --shared-lib-name which can be used to specify the name of
+ the shared library (DLL) implementing the Python runtime that is required
+ for the frozen executable to work. This option is also particularly useful
+ when cross compiling since the normal method for determining this
+ information cannot be used.
+ 3) Added option --zip-include which allows for additional files to be added
+ to the zip file that contains the modules that implement the Python
+ script. Thanks to Barray Warsaw for providing the initial patch.
+ 4) Added support for handling read-only files properly. Thanks to Peter
+ Grayson for pointing out the problem and providing a solution.
+ 5) Added support for a frozen executable to be a symbolic link. Thanks to
+ Robert Kiendl for providing the initial patch.
+ 6) Enhanced the support for running a frozen executable that uses an existing
+ Python installation to locate modules it requires. This is primarily of
+ use for embedding Python where the interface is C but the ability to run
+ from source is still desired.
+ 7) Modified the documentation to indicate that building from source on
+ Windows currently requires the mingw compiler (http://www.mingw.org).
+ 8) Workaround the problem in Python 2.3 (fixed in Python 2.4) which causes a
+ broken module to be left in sys.modules if an ImportError takes place
+ during the execution of the code in that module. Thanks to Roger Binns
+ for pointing this out.
+
+Changes from 3.0 beta3 to 3.0
+ 1) Ensure that ldd is only run on extension modules.
+ 2) Allow for using a compiler other than gcc for building the frozen base
+ executables by setting the environment variable CC.
+ 3) Ensure that the import lock is not held while executing the main script;
+ otherwise, attempts to import a module within a thread will hang that
+ thread as noted by Roger Binns.
+ 4) Added support for replacing the paths in all frozen modules with something
+ else (so that for example the path of the machine on which the freezing
+ was done is not displayed in tracebacks)
+
+Changes from 3.0 beta2 to 3.0 beta3
+ 1) Explicitly include the warnings module so that at runtime warnings are
+ suppressed as when running Python normally.
+ 2) Improve the extension loader so that an ImportError is raised when the
+ dynamic module is not located; otherwise an error about missing attributes
+ is raised instead.
+ 3) Extension loaders are only created when copying dependencies since the
+ normal module should be loadable in the situation where a Python
+ installation is available.
+ 4) Added support for Python 2.4.
+ 5) Fixed the dependency checking for wxPython to be a little more
+ intelligent.
+
+Changes from 3.0 beta1 to 3.0 beta2
+ 1) Fix issues with locating the initscripts and bases relative to the
+ directory in which the executable was started.
+ 2) Added new base executable ConsoleKeepPath which is used when an existing
+ Python installation is required (such as for FreezePython itself).
+ 3) Forced the existence of a Python installation to be ignored when using the
+ standard Console base executable.
+ 4) Remove the existing file when copying dependent files; otherwise, an error
+ is raised when attempting to overwrite read-only files.
+ 5) Added option -O (or -OO) to FreezePython to set the optimization used when
+ generating bytecode.
+
+Changes from 2.2 to 3.0 beta1
+ 1) cx_Freeze now requires Python 2.3 or higher since it takes advantage of
+ the ability of Python 2.3 and higher to import modules from zip files.
+ This makes the freezing process considerably simpler and also allows for
+ the execution of multiple frozen packages (such as found in COM servers or
+ shared libraries) without requiring modification to the Python modules.
+ 2) All external dependencies have been removed. cx_Freeze now only requires
+ a standard Python distribution to do its work.
+ 3) Added the ability to define the initialization scripts that cx_Freeze uses
+ on startup of the frozen program. Previously, these scripts were written
+ in C and could not easily be changed; now they are written in Python and
+ can be found in the initscripts directory (and chosen with the
+ new --init-script option to FreezePython).
+ 4) The base executable ConsoleSetLibPath has been removed and replaced with
+ the initscript ConsoleSetLibPath.
+ 5) Removed base executables for Win32 services and Win32 COM servers. This
+ functionality will be restored in the future but it is not currently in a
+ state that is ready for release. If this functionality is required, please
+ use py2exe or contact me for my work in progress.
+ 6) The attribute sys.frozen is now set so that more recent pywin32 modules
+ work as expected when frozen.
+ 7) Added option --include-path to FreezePython to allow overriding of
+ sys.path without modifying the environment variable PYTHONPATH.
+ 8) Added option --target-dir/--install-dir to specify the directory in which
+ the frozen executable and its dependencies will be placed.
+ 9) Removed the option --shared-lib since it was used for building shared
+ libraries and can be managed with the initscript SharedLib.py.
+10) MakeFrozenBases.py now checks the platform specific include directory as
+ requested by Michael Partridge.
+
+
+Changes from 2.1 to 2.2
+ 1) Add option (--ext-list-file) to FreezePython to write the list of
+ extensions copied to the installation directory to a file. This option is
+ useful in cases where multiple builds are performed into the same
+ installation directory.
+ 2) Pass the arguments on the command line through to Win32 GUI applications.
+ Thanks to Michael Porter for pointing this out.
+ 3) Link directly against the python DLL when building the frozen bases on
+ Windows, thus eliminating the need for building an import library.
+ 4) Force sys.path to include the directory in which the script to be frozen
+ is found.
+ 5) Make sure that the installation directory exists before attempting to
+ copy the target binary into it.
+ 6) The Win32GUI base has been modified to display fatal errors in message
+ boxes, rather than printing errors to stderr, since on Windows the
+ standard file IO handles are all closed.
+
+Changes from 2.0 to 2.1
+ 1) Remove dependency on Python 2.2. Thanks to Paul Moore for not only
+ pointing it out but providing patches.
+ 2) Set up the list of frozen modules in advance, rather than doing it after
+ Python is initialized so that implicit imports done by Python can be
+ satisfied. The bug in Python 2.3 that demonstrated this issue has been
+ fixed in the first release candidate. Thanks to Thomas Heller for pointing
+ out the obvious in this instance!
+ 3) Added additional base executable (ConsoleSetLibPath) to support setting
+ the LD_LIBRARY_PATH variable on Unix platforms and restarting the
+ executable to put the new setting into effect. This is primarily of use
+ in distributing wxPython applications on Unix where the shared library
+ has an embedded RPATH value which can cause problems.
+ 4) Small improvements of documentation based on feedback from several people.
+ 5) Print information about the files written or copied during the freezing
+ process.
+ 6) Do not copy extensions when freezing if the path is being overridden since
+ it is expected that a full Python installation is available to the target
+ users of the frozen binary.
+ 7) Provide meaningful error message when the wxPython library cannot be
+ found during the freezing process.
+
+Changes from 1.1 to 2.0
+ 1) Added support for in process (DLL) COM servers using PythonCOM.
+ 2) Ensured that the frozen flag is set prior to determining the full path for
+ the program in order to avoid warnings about Python not being found on
+ some platforms.
+ 3) Added include file and resource file to the source tree to avoid the
+ dependency on the Wine message compiler for Win32 builds.
+ 4) Dropped the option --copy-extensions; this now happens automatically since
+ the resulting binary is useless without them.
+ 5) Added a sample for building a Win32 service.
+ 6) Make use of improved modules from Python 2.3 (which function under 2.2)
+
+Changes from 1.0 to 1.1
+ 1) Fixed import error with C extensions in packages; thanks to Thomas Heller
+ for pointing out the solution to this problem.
+ 2) Added options to FreezePython to allow for the inclusion of modules which
+ will not be found by the module finder (--include-modules) and the
+ exclusion of modules which will be found by the module finder but should
+ not be included (--exclude-modules).
+ 3) Fixed typo in README.txt.
+
diff --git a/installer/cx_Freeze/LICENSE.txt b/installer/cx_Freeze/LICENSE.txt
new file mode 100644
index 0000000000..cb9ee05a8a
--- /dev/null
+++ b/installer/cx_Freeze/LICENSE.txt
@@ -0,0 +1,53 @@
+Copyright 2007-2008, Colt Engineering, Edmonton, Alberta, Canada.
+Copyright 2001-2006, Computronix (Canada) Ltd., Edmonton, Alberta, Canada.
+All rights reserved.
+
+NOTE: this license is derived from the Python Software Foundation License
+which can be found at http://www.python.org/psf/license
+
+License for cx_Freeze 4.0.1
+---------------------------
+
+1. This LICENSE AGREEMENT is between the copyright holders and the Individual
+ or Organization ("Licensee") accessing and otherwise using cx_Freeze
+ software in source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, the
+ copyright holders hereby grant Licensee a nonexclusive, royalty-free,
+ world-wide license to reproduce, analyze, test, perform and/or display
+ publicly, prepare derivative works, distribute, and otherwise use cx_Freeze
+ alone or in any derivative version, provided, however, that this License
+ Agreement and this notice of copyright are retained in cx_Freeze alone or in
+ any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+ incorporates cx_Freeze or any part thereof, and wants to make the derivative
+ work available to others as provided herein, then Licensee hereby agrees to
+ include in any such work a brief summary of the changes made to cx_Freeze.
+
+4. The copyright holders are making cx_Freeze available to Licensee on an
+ "AS IS" basis. THE COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES,
+ EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, THE COPYRIGHT
+ HOLDERS MAKE NO AND DISCLAIM ANY REPRESENTATION OR WARRANTY OF
+ MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF
+ CX_FREEZE WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. THE COPYRIGHT HOLDERS SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF
+ CX_FREEZE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+ A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING CX_FREEZE, OR ANY
+ DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material breach
+ of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any relationship
+ of agency, partnership, or joint venture between the copyright holders and
+ Licensee. This License Agreement does not grant permission to use
+ copyright holder's trademarks or trade name in a trademark sense to endorse
+ or promote products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using cx_Freeze, Licensee agrees to be
+ bound by the terms and conditions of this License Agreement.
+
+Computronix is a registered trademark of Computronix (Canada) Ltd.
+
diff --git a/installer/cx_Freeze/MANIFEST.in b/installer/cx_Freeze/MANIFEST.in
new file mode 100644
index 0000000000..2348a66973
--- /dev/null
+++ b/installer/cx_Freeze/MANIFEST.in
@@ -0,0 +1,6 @@
+include MANIFEST.in
+include *.txt
+recursive-include doc *.html
+recursive-include initscripts *.py
+recursive-include samples *.py
+recursive-include source *.c *.rc
diff --git a/installer/cx_Freeze/PKG-INFO b/installer/cx_Freeze/PKG-INFO
new file mode 100644
index 0000000000..aa53b57914
--- /dev/null
+++ b/installer/cx_Freeze/PKG-INFO
@@ -0,0 +1,22 @@
+Metadata-Version: 1.0
+Name: cx_Freeze
+Version: 4.0.1
+Summary: create standalone executables from Python scripts
+Home-page: http://cx-freeze.sourceforge.net
+Author: Anthony Tuininga
+Author-email: anthony.tuininga@gmail.com
+License: Python Software Foundation License
+Description: create standalone executables from Python scripts
+Keywords: freeze
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Python Software Foundation License
+Classifier: Natural Language :: English
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: C
+Classifier: Programming Language :: Python
+Classifier: Topic :: Software Development :: Build Tools
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: System :: Software Distribution
+Classifier: Topic :: Utilities
diff --git a/installer/cx_Freeze/README.txt b/installer/cx_Freeze/README.txt
new file mode 100644
index 0000000000..1ac67dc749
--- /dev/null
+++ b/installer/cx_Freeze/README.txt
@@ -0,0 +1,12 @@
+Please see cx_Freeze.html for documentation on how to use cx_Freeze.
+
+To build:
+
+python setup.py build
+python setup.py install
+
+On Windows I have used the MinGW compiler (http://www.mingw.org)
+
+python setup.py build --compiler=mingw32
+python setup.py build --compiler=mingw32 install
+
diff --git a/installer/cx_Freeze/cx_Freeze/__init__.py b/installer/cx_Freeze/cx_Freeze/__init__.py
new file mode 100644
index 0000000000..545883eb3e
--- /dev/null
+++ b/installer/cx_Freeze/cx_Freeze/__init__.py
@@ -0,0 +1,14 @@
+version = "4.0.1"
+
+import sys
+from dist import *
+if sys.platform == "win32" and sys.version_info[:2] >= (2, 5):
+ from windist import *
+from finder import *
+from freezer import *
+from main import *
+
+del dist
+del finder
+del freezer
+
diff --git a/installer/cx_Freeze/cx_Freeze/dist.py b/installer/cx_Freeze/cx_Freeze/dist.py
new file mode 100644
index 0000000000..c2af2ac623
--- /dev/null
+++ b/installer/cx_Freeze/cx_Freeze/dist.py
@@ -0,0 +1,279 @@
+import distutils.command.bdist_rpm
+import distutils.command.build
+import distutils.command.install
+import distutils.core
+import distutils.dir_util
+import distutils.dist
+import distutils.util
+import distutils.version
+import os
+import sys
+
+import cx_Freeze
+
+__all__ = [ "bdist_rpm", "build", "build_exe", "install", "install_exe",
+ "setup" ]
+
+class Distribution(distutils.dist.Distribution):
+
+ def __init__(self, attrs):
+ self.executables = []
+ distutils.dist.Distribution.__init__(self, attrs)
+
+
+class bdist_rpm(distutils.command.bdist_rpm.bdist_rpm):
+
+ def finalize_options(self):
+ distutils.command.bdist_rpm.bdist_rpm.finalize_options(self)
+ self.use_rpm_opt_flags = 1
+
+ def _make_spec_file(self):
+ contents = distutils.command.bdist_rpm.bdist_rpm._make_spec_file(self)
+ return [c for c in contents if c != 'BuildArch: noarch']
+
+
+class build(distutils.command.build.build):
+ user_options = distutils.command.build.build.user_options + [
+ ('build-exe=', None, 'build directory for executables')
+ ]
+
+ def get_sub_commands(self):
+ subCommands = distutils.command.build.build.get_sub_commands(self)
+ if self.distribution.executables:
+ subCommands.append("build_exe")
+ return subCommands
+
+ def initialize_options(self):
+ distutils.command.build.build.initialize_options(self)
+ self.build_exe = None
+
+ def finalize_options(self):
+ distutils.command.build.build.finalize_options(self)
+ if self.build_exe is None:
+ dirName = "exe.%s-%s" % \
+ (distutils.util.get_platform(), sys.version[0:3])
+ self.build_exe = os.path.join(self.build_base, dirName)
+
+
+class build_exe(distutils.core.Command):
+ description = "build executables from Python scripts"
+ user_options = [
+ ('build-exe=', 'b',
+ 'directory for built executables'),
+ ('optimize=', 'O',
+ 'optimization level: -O1 for "python -O", '
+ '-O2 for "python -OO" and -O0 to disable [default: -O0]'),
+ ('excludes=', 'e',
+ 'comma-separated list of modules to exclude'),
+ ('includes=', 'i',
+ 'comma-separated list of modules to include'),
+ ('packages=', 'p',
+ 'comma-separated list of packages to include'),
+ ('replace-paths=', None,
+ 'comma-separated list of paths to replace in included modules'),
+ ('path=', None,
+ 'comma-separated list of paths to search'),
+ ('init-script=', 'i',
+ 'name of script to use during initialization'),
+ ('base=', None,
+ 'name of base executable to use'),
+ ('compressed', 'c',
+ 'create a compressed zipfile'),
+ ('copy-dependent-files', None,
+ 'copy all dependent files'),
+ ('create-shared-zip', None,
+ 'create a shared zip file containing shared modules'),
+ ('append-script-to-exe', None,
+ 'append the script module to the exe'),
+ ('include-in-shared-zip', None,
+ 'include the script module in the shared zip file'),
+ ('icon', None,
+ 'include the icon along with the frozen executable(s)'),
+ ('constants=', None,
+ 'comma-separated list of constants to include'),
+ ('include-files=', 'f',
+ 'list of tuples of additional files to include in distribution'),
+ ('bin-includes', None,
+ 'list of names of files to include when determining dependencies'),
+ ('bin-excludes', None,
+ 'list of names of files to exclude when determining dependencies')
+ ]
+ boolean_options = ["compressed", "copy_dependent_files",
+ "create_shared_zip", "append_script_to_exe",
+ "include_in_shared_zip"]
+
+ def _normalize(self, attrName):
+ value = getattr(self, attrName)
+ if value is None:
+ normalizedValue = []
+ elif isinstance(value, basestring):
+ normalizedValue = value.split()
+ else:
+ normalizedValue = list(value)
+ setattr(self, attrName, normalizedValue)
+
+ def initialize_options(self):
+ self.optimize = 0
+ self.build_exe = None
+ self.excludes = []
+ self.includes = []
+ self.packages = []
+ self.replace_paths = []
+ self.compressed = None
+ self.copy_dependent_files = None
+ self.init_script = None
+ self.base = None
+ self.path = None
+ self.create_shared_zip = None
+ self.append_script_to_exe = None
+ self.include_in_shared_zip = None
+ self.icon = None
+ self.constants = []
+ self.include_files = []
+ self.bin_excludes = []
+ self.bin_includes = []
+
+ def finalize_options(self):
+ self.set_undefined_options('build', ('build_exe', 'build_exe'))
+ self.optimize = int(self.optimize)
+ self._normalize("excludes")
+ self._normalize("includes")
+ self._normalize("packages")
+ self._normalize("constants")
+
+ def run(self):
+ metadata = self.distribution.metadata
+ constantsModule = cx_Freeze.ConstantsModule(metadata.version)
+ for constant in self.constants:
+ parts = constant.split("=")
+ if len(parts) == 1:
+ name = constant
+ value = None
+ else:
+ name, stringValue = parts
+ value = eval(stringValue)
+ constantsModule.values[name] = value
+ freezer = cx_Freeze.Freezer(self.distribution.executables,
+ [constantsModule], self.includes, self.excludes, self.packages,
+ self.replace_paths, self.compressed, self.optimize,
+ self.copy_dependent_files, self.init_script, self.base,
+ self.path, self.create_shared_zip, self.append_script_to_exe,
+ self.include_in_shared_zip, self.build_exe, icon = self.icon,
+ includeFiles = self.include_files,
+ binIncludes = self.bin_includes,
+ binExcludes = self.bin_excludes)
+ freezer.Freeze()
+
+
+class install(distutils.command.install.install):
+ user_options = distutils.command.install.install.user_options + [
+ ('install-exe=', None,
+ 'installation directory for executables')
+ ]
+
+ def expand_dirs(self):
+ distutils.command.install.install.expand_dirs(self)
+ self._expand_attrs(['install_exe'])
+
+ def get_sub_commands(self):
+ subCommands = distutils.command.install.install.get_sub_commands(self)
+ if self.distribution.executables:
+ subCommands.append("install_exe")
+ return [s for s in subCommands if s != "install_egg_info"]
+
+ def initialize_options(self):
+ distutils.command.install.install.initialize_options(self)
+ self.install_exe = None
+
+ def finalize_options(self):
+ if self.prefix is None and sys.platform == "win32":
+ import _winreg
+ key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
+ r"Software\Microsoft\Windows\CurrentVersion")
+ prefix = str(_winreg.QueryValueEx(key, "ProgramFilesDir")[0])
+ metadata = self.distribution.metadata
+ dirName = "%s-%s" % (metadata.name, metadata.version)
+ self.prefix = "%s/%s" % (prefix, dirName)
+ distutils.command.install.install.finalize_options(self)
+ self.convert_paths('exe')
+ if self.root is not None:
+ self.change_roots('exe')
+
+ def select_scheme(self, name):
+ distutils.command.install.install.select_scheme(self, name)
+ if self.install_exe is None:
+ if sys.platform == "win32":
+ self.install_exe = '$base'
+ else:
+ metadata = self.distribution.metadata
+ dirName = "%s-%s" % (metadata.name, metadata.version)
+ self.install_exe = '$base/lib/%s' % dirName
+
+
+class install_exe(distutils.core.Command):
+ description = "install executables built from Python scripts"
+ user_options = [
+ ('install-dir=', 'd', 'directory to install executables to'),
+ ('build-dir=', 'b', 'build directory (where to install from)'),
+ ('force', 'f', 'force installation (overwrite existing files)'),
+ ('skip-build', None, 'skip the build steps')
+ ]
+
+ def initialize_options(self):
+ self.install_dir = None
+ self.force = 0
+ self.build_dir = None
+ self.skip_build = None
+
+ def finalize_options(self):
+ self.set_undefined_options('build', ('build_exe', 'build_dir'))
+ self.set_undefined_options('install',
+ ('install_exe', 'install_dir'),
+ ('force', 'force'),
+ ('skip_build', 'skip_build'))
+
+ def run(self):
+ if not self.skip_build:
+ self.run_command('build_exe')
+ self.outfiles = self.copy_tree(self.build_dir, self.install_dir)
+ if sys.platform != "win32":
+ baseDir = os.path.dirname(os.path.dirname(self.install_dir))
+ binDir = os.path.join(baseDir, "bin")
+ if not os.path.exists(binDir):
+ os.makedirs(binDir)
+ sourceDir = os.path.join("..", self.install_dir[len(baseDir) + 1:])
+ for executable in self.distribution.executables:
+ name = os.path.basename(executable.targetName)
+ source = os.path.join(sourceDir, name)
+ target = os.path.join(binDir, name)
+ if os.path.exists(target):
+ os.unlink(target)
+ os.symlink(source, target)
+ self.outfiles.append(target)
+
+ def get_inputs(self):
+ return self.distribution.executables or []
+
+ def get_outputs(self):
+ return self.outfiles or []
+
+
+def _AddCommandClass(commandClasses, name, cls):
+ if name not in commandClasses:
+ commandClasses[name] = cls
+
+
+def setup(**attrs):
+ attrs["distclass"] = Distribution
+ commandClasses = attrs.setdefault("cmdclass", {})
+ if sys.platform == "win32":
+ if sys.version_info[:2] >= (2, 5):
+ _AddCommandClass(commandClasses, "bdist_msi", cx_Freeze.bdist_msi)
+ else:
+ _AddCommandClass(commandClasses, "bdist_rpm", cx_Freeze.bdist_rpm)
+ _AddCommandClass(commandClasses, "build", build)
+ _AddCommandClass(commandClasses, "build_exe", build_exe)
+ _AddCommandClass(commandClasses, "install", install)
+ _AddCommandClass(commandClasses, "install_exe", install_exe)
+ distutils.core.setup(**attrs)
+
diff --git a/installer/cx_Freeze/cx_Freeze/finder.py b/installer/cx_Freeze/cx_Freeze/finder.py
new file mode 100644
index 0000000000..f815db97be
--- /dev/null
+++ b/installer/cx_Freeze/cx_Freeze/finder.py
@@ -0,0 +1,455 @@
+"""
+Base class for finding modules.
+"""
+
+import dis
+import imp
+import marshal
+import new
+import opcode
+import os
+import sys
+import zipfile
+
+import cx_Freeze.hooks
+
+BUILD_LIST = opcode.opmap["BUILD_LIST"]
+INPLACE_ADD = opcode.opmap["INPLACE_ADD"]
+LOAD_CONST = opcode.opmap["LOAD_CONST"]
+IMPORT_NAME = opcode.opmap["IMPORT_NAME"]
+IMPORT_FROM = opcode.opmap["IMPORT_FROM"]
+STORE_NAME = opcode.opmap["STORE_NAME"]
+STORE_GLOBAL = opcode.opmap["STORE_GLOBAL"]
+STORE_OPS = (STORE_NAME, STORE_GLOBAL)
+
+__all__ = [ "Module", "ModuleFinder" ]
+
+class ModuleFinder(object):
+
+ def __init__(self, includeFiles, excludes, path, replacePaths):
+ self.includeFiles = includeFiles
+ self.excludes = dict.fromkeys(excludes)
+ self.replacePaths = replacePaths
+ self.path = path or sys.path
+ self.modules = []
+ self.aliases = {}
+ self._modules = dict.fromkeys(excludes)
+ self._builtinModules = dict.fromkeys(sys.builtin_module_names)
+ self._badModules = {}
+ self._zipFileEntries = {}
+ self._zipFiles = {}
+ cx_Freeze.hooks.initialize(self)
+
+ def _AddModule(self, name):
+ """Add a module to the list of modules but if one is already found,
+ then return it instead; this is done so that packages can be
+ handled properly."""
+ module = self._modules.get(name)
+ if module is None:
+ module = self._modules[name] = Module(name)
+ self.modules.append(module)
+ if name in self._badModules:
+ del self._badModules[name]
+ return module
+
+ def _DetermineParent(self, caller):
+ """Determine the parent to use when searching packages."""
+ if caller is not None:
+ if caller.path is not None:
+ return caller
+ return self._GetParentByName(caller.name)
+
+ def _EnsureFromList(self, caller, packageModule, fromList,
+ deferredImports):
+ """Ensure that the from list is satisfied. This is only necessary for
+ package modules. If the caller is the package itself, actually
+ attempt to import right then since it must be a submodule; otherwise
+ defer until after all global names are defined in order to avoid
+ spurious complaints about missing modules."""
+ if caller is not packageModule:
+ deferredImports.append((packageModule, fromList))
+ else:
+ if fromList == ("*",):
+ fromList = packageModule.allNames
+ for name in fromList:
+ if name in packageModule.globalNames:
+ continue
+ subModuleName = "%s.%s" % (packageModule.name, name)
+ self._ImportModule(subModuleName, deferredImports, caller)
+
+ def _FindModule(self, name, path):
+ try:
+ return imp.find_module(name, path)
+ except ImportError:
+ if not path:
+ path = []
+ for location in path:
+ if name in self._zipFileEntries:
+ break
+ if location in self._zipFiles:
+ continue
+ if os.path.isdir(location) or not zipfile.is_zipfile(location):
+ self._zipFiles[location] = None
+ continue
+ zip = zipfile.ZipFile(location)
+ for archiveName in zip.namelist():
+ baseName, ext = os.path.splitext(archiveName)
+ if ext not in ('.pyc', '.pyo'):
+ continue
+ moduleName = ".".join(baseName.split("/"))
+ if moduleName in self._zipFileEntries:
+ continue
+ self._zipFileEntries[moduleName] = (zip, archiveName)
+ self._zipFiles[location] = None
+ info = self._zipFileEntries.get(name)
+ if info is not None:
+ zip, archiveName = info
+ fp = zip.read(archiveName)
+ info = (".pyc", "rb", imp.PY_COMPILED)
+ return fp, os.path.join(zip.filename, archiveName), info
+ raise
+
+ def _GetParentByName(self, name):
+ """Return the parent module given the name of a module."""
+ pos = name.rfind(".")
+ if pos > 0:
+ parentName = name[:pos]
+ return self._modules[parentName]
+
+ def _ImportAllSubModules(self, module, deferredImports, recursive = True):
+ """Import all sub modules to the given package."""
+ suffixes = dict.fromkeys([s[0] for s in imp.get_suffixes()])
+ for dir in module.path:
+ try:
+ fileNames = os.listdir(dir)
+ except os.error:
+ continue
+ for fileName in fileNames:
+ name, ext = os.path.splitext(fileName)
+ if ext not in suffixes:
+ continue
+ if name == "__init__":
+ continue
+ subModuleName = "%s.%s" % (module.name, name)
+ subModule, returnError = \
+ self._InternalImportModule(subModuleName,
+ deferredImports)
+ if returnError and subModule is None:
+ raise ImportError, "No module named %s" % subModuleName
+ module.globalNames[name] = None
+ if subModule.path and recursive:
+ self._ImportAllSubModules(subModule, deferredImports,
+ recursive)
+
+ def _ImportDeferredImports(self, deferredImports):
+ """Import any sub modules that were deferred, if applicable."""
+ while deferredImports:
+ newDeferredImports = []
+ for packageModule, subModuleNames in deferredImports:
+ self._EnsureFromList(packageModule, packageModule,
+ subModuleNames, newDeferredImports)
+ deferredImports = newDeferredImports
+
+ def _ImportModule(self, name, deferredImports, caller = None,
+ relativeImportIndex = 0):
+ """Attempt to find the named module and return it or None if no module
+ by that name could be found."""
+
+ # absolute import (available in Python 2.5 and up)
+ # the name given is the only name that will be searched
+ if relativeImportIndex == 0:
+ module, returnError = self._InternalImportModule(name,
+ deferredImports)
+
+ # old style relative import (only possibility in Python 2.4 and prior)
+ # the name given is tried in all parents until a match is found and if
+ # no match is found, the global namespace is searched
+ elif relativeImportIndex < 0:
+ parent = self._DetermineParent(caller)
+ while parent is not None:
+ fullName = "%s.%s" % (parent.name, name)
+ module, returnError = self._InternalImportModule(fullName,
+ deferredImports)
+ if module is not None:
+ parent.globalNames[name] = None
+ return module
+ parent = self._GetParentByName(parent.name)
+ module, returnError = self._InternalImportModule(name,
+ deferredImports)
+
+ # new style relative import (available in Python 2.5 and up)
+ # the index indicates how many levels to traverse and only that level
+ # is searched for the named module
+ elif relativeImportIndex > 0:
+ parent = caller
+ if parent.path is not None:
+ relativeImportIndex -= 1
+ while parent is not None and relativeImportIndex > 0:
+ parent = self._GetParentByName(parent.name)
+ relativeImportIndex -= 1
+ if parent is None:
+ module = None
+ returnError = True
+ elif not name:
+ module = parent
+ else:
+ name = "%s.%s" % (parent.name, name)
+ module, returnError = self._InternalImportModule(name,
+ deferredImports)
+
+ # if module not found, track that fact
+ if module is None:
+ if caller is None:
+ raise ImportError, "No module named %s" % name
+ self._RunHook("missing", name, caller)
+ if returnError and name not in caller.ignoreNames:
+ callers = self._badModules.setdefault(name, {})
+ callers[caller.name] = None
+
+ return module
+
+ def _InternalImportModule(self, name, deferredImports):
+ """Internal method used for importing a module which assumes that the
+ name given is an absolute name. None is returned if the module
+ cannot be found."""
+ try:
+ return self._modules[name], False
+ except KeyError:
+ pass
+ if name in self._builtinModules:
+ module = self._AddModule(name)
+ self._RunHook("load", module.name, module)
+ return module, False
+ pos = name.rfind(".")
+ if pos < 0:
+ path = self.path
+ searchName = name
+ parentModule = None
+ else:
+ parentName = name[:pos]
+ parentModule, returnError = \
+ self._InternalImportModule(parentName, deferredImports)
+ if parentModule is None:
+ return None, returnError
+ path = parentModule.path
+ searchName = name[pos + 1:]
+ if name in self.aliases:
+ actualName = self.aliases[name]
+ module, returnError = \
+ self._InternalImportModule(actualName, deferredImports)
+ self._modules[name] = module
+ return module, returnError
+ try:
+ fp, path, info = self._FindModule(searchName, path)
+ except ImportError:
+ self._modules[name] = None
+ return None, True
+ module = self._LoadModule(name, fp, path, info, deferredImports,
+ parentModule)
+ return module, False
+
+ def _LoadModule(self, name, fp, path, info, deferredImports,
+ parent = None):
+ """Load the module, given the information acquired by the finder."""
+ suffix, mode, type = info
+ if type == imp.PKG_DIRECTORY:
+ return self._LoadPackage(name, path, parent, deferredImports)
+ module = self._AddModule(name)
+ module.file = path
+ module.parent = parent
+ if type == imp.PY_SOURCE:
+ module.code = compile(fp.read() + "\n", path, "exec")
+ elif type == imp.PY_COMPILED:
+ if isinstance(fp, str):
+ magic = fp[:4]
+ else:
+ magic = fp.read(4)
+ if magic != imp.get_magic():
+ raise ImportError, "Bad magic number in %s" % path
+ if isinstance(fp, str):
+ module.code = marshal.loads(fp[8:])
+ module.inZipFile = True
+ else:
+ fp.read(4)
+ module.code = marshal.load(fp)
+ self._RunHook("load", module.name, module)
+ if module.code is not None:
+ if self.replacePaths:
+ topLevelModule = module
+ while topLevelModule.parent is not None:
+ topLevelModule = topLevelModule.parent
+ module.code = self._ReplacePathsInCode(topLevelModule,
+ module.code)
+ self._ScanCode(module.code, module, deferredImports)
+ return module
+
+ def _LoadPackage(self, name, path, parent, deferredImports):
+ """Load the package, given its name and path."""
+ module = self._AddModule(name)
+ module.path = [path]
+ fp, path, info = imp.find_module("__init__", module.path)
+ self._LoadModule(name, fp, path, info, deferredImports, parent)
+ return module
+
+ def _ReplacePathsInCode(self, topLevelModule, co):
+ """Replace paths in the code as directed, returning a new code object
+ with the modified paths in place."""
+ origFileName = newFileName = os.path.normpath(co.co_filename)
+ for searchValue, replaceValue in self.replacePaths:
+ if searchValue == "*":
+ searchValue = os.path.dirname(topLevelModule.file)
+ if topLevelModule.path:
+ searchValue = os.path.dirname(searchValue)
+ if searchValue:
+ searchValue = searchValue + os.pathsep
+ elif not origFileName.startswith(searchValue):
+ continue
+ newFileName = replaceValue + origFileName[len(searchValue):]
+ break
+ constants = list(co.co_consts)
+ for i, value in enumerate(constants):
+ if isinstance(value, type(co)):
+ constants[i] = self._ReplacePathsInCode(topLevelModule, value)
+ return new.code(co.co_argcount, co.co_nlocals, co.co_stacksize,
+ co.co_flags, co.co_code, tuple(constants), co.co_names,
+ co.co_varnames, newFileName, co.co_name, co.co_firstlineno,
+ co.co_lnotab, co.co_freevars, co.co_cellvars)
+
+ def _RunHook(self, hookName, moduleName, *args):
+ """Run hook for the given module if one is present."""
+ name = "%s_%s" % (hookName, moduleName.replace(".", "_"))
+ method = getattr(cx_Freeze.hooks, name, None)
+ if method is not None:
+ method(self, *args)
+
+ def _ScanCode(self, co, module, deferredImports):
+ """Scan code, looking for imported modules and keeping track of the
+ constants that have been created in order to better tell which
+ modules are truly missing."""
+ opIndex = 0
+ arguments = []
+ code = co.co_code
+ numOps = len(code)
+ while opIndex < numOps:
+ op = ord(code[opIndex])
+ opIndex += 1
+ if op >= dis.HAVE_ARGUMENT:
+ opArg = ord(code[opIndex]) + ord(code[opIndex + 1]) * 256
+ opIndex += 2
+ if op == LOAD_CONST:
+ arguments.append(co.co_consts[opArg])
+ elif op == IMPORT_NAME:
+ name = co.co_names[opArg]
+ if len(arguments) == 2:
+ relativeImportIndex, fromList = arguments
+ else:
+ relativeImportIndex = -1
+ fromList, = arguments
+ if name not in module.excludeNames:
+ subModule = self._ImportModule(name, deferredImports,
+ module, relativeImportIndex)
+ if subModule is not None:
+ module.globalNames.update(subModule.globalNames)
+ if fromList and subModule.path is not None:
+ self._EnsureFromList(module, subModule, fromList,
+ deferredImports)
+ elif op == IMPORT_FROM:
+ opIndex += 3
+ elif op not in (BUILD_LIST, INPLACE_ADD):
+ if op in STORE_OPS:
+ name = co.co_names[opArg]
+ if name == "__all__":
+ module.allNames.extend(arguments)
+ module.globalNames[name] = None
+ arguments = []
+ for constant in co.co_consts:
+ if isinstance(constant, type(co)):
+ self._ScanCode(constant, module, deferredImports)
+
+ def AddAlias(self, name, aliasFor):
+ """Add an alias for a particular module; when an attempt is made to
+ import a module using the alias name, import the actual name
+ instead."""
+ self.aliases[name] = aliasFor
+
+ def ExcludeModule(self, name):
+ """Exclude the named module from the resulting frozen executable."""
+ self.excludes[name] = None
+ self._modules[name] = None
+
+ def IncludeFile(self, path, moduleName = None):
+ """Include the named file as a module in the frozen executable."""
+ name, ext = os.path.splitext(os.path.basename(path))
+ if moduleName is None:
+ moduleName = name
+ info = (ext, "r", imp.PY_SOURCE)
+ deferredImports = []
+ module = self._LoadModule(moduleName, file(path, "U"), path, info,
+ deferredImports)
+ self._ImportDeferredImports(deferredImports)
+ return module
+
+ def IncludeFiles(self, sourcePath, targetPath):
+ """Include the files in the given directory in the target build."""
+ self.includeFiles.append((sourcePath, targetPath))
+
+ def IncludeModule(self, name):
+ """Include the named module in the frozen executable."""
+ deferredImports = []
+ module = self._ImportModule(name, deferredImports)
+ self._ImportDeferredImports(deferredImports)
+ return module
+
+ def IncludePackage(self, name):
+ """Include the named package and any submodules in the frozen
+ executable."""
+ deferredImports = []
+ module = self._ImportModule(name, deferredImports)
+ if module.path:
+ self._ImportAllSubModules(module, deferredImports)
+ self._ImportDeferredImports(deferredImports)
+ return module
+
+ def ReportMissingModules(self):
+ if self._badModules:
+ print "Missing modules:"
+ names = self._badModules.keys()
+ names.sort()
+ for name in names:
+ callers = self._badModules[name].keys()
+ callers.sort()
+ print "?", name, "imported from", ", ".join(callers)
+ print
+
+
+class Module(object):
+
+ def __init__(self, name):
+ self.name = name
+ self.file = None
+ self.path = None
+ self.code = None
+ self.parent = None
+ self.globalNames = {}
+ self.excludeNames = {}
+ self.ignoreNames = {}
+ self.allNames = []
+ self.inZipFile = False
+
+ def __repr__(self):
+ parts = ["name=%s" % repr(self.name)]
+ if self.file is not None:
+ parts.append("file=%s" % repr(self.file))
+ if self.path is not None:
+ parts.append("path=%s" % repr(self.path))
+ return "" % ", ".join(parts)
+
+ def AddGlobalName(self, name):
+ self.globalNames[name] = None
+
+ def ExcludeName(self, name):
+ self.excludeNames[name] = None
+
+ def IgnoreName(self, name):
+ self.ignoreNames[name] = None
+
diff --git a/installer/cx_Freeze/cx_Freeze/freezer.py b/installer/cx_Freeze/cx_Freeze/freezer.py
new file mode 100644
index 0000000000..e0739e8a4e
--- /dev/null
+++ b/installer/cx_Freeze/cx_Freeze/freezer.py
@@ -0,0 +1,550 @@
+"""
+Base class for freezing scripts into executables.
+"""
+
+import datetime
+import distutils.sysconfig
+import imp
+import marshal
+import os
+import shutil
+import socket
+import stat
+import struct
+import sys
+import time
+import zipfile
+
+import cx_Freeze
+import cx_Freeze.util
+
+__all__ = [ "ConfigError", "ConstantsModule", "Executable", "Freezer" ]
+
+if sys.platform == "win32":
+ pythonDll = "python%s%s.dll" % sys.version_info[:2]
+ GLOBAL_BIN_PATH_EXCLUDES = [cx_Freeze.util.GetSystemDir()]
+ GLOBAL_BIN_INCLUDES = [
+ pythonDll,
+ "gdiplus.dll",
+ "mfc71.dll",
+ "msvcp71.dll",
+ "msvcr71.dll"
+ ]
+ GLOBAL_BIN_EXCLUDES = [
+ "comctl32.dll",
+ "oci.dll",
+ "cx_Logging.pyd"
+ ]
+else:
+ extension = distutils.sysconfig.get_config_var("SO")
+ pythonSharedLib = "libpython%s.%s%s" % \
+ (sys.version_info[:2] + (extension,))
+ GLOBAL_BIN_INCLUDES = [pythonSharedLib]
+ GLOBAL_BIN_EXCLUDES = [
+ "libclntsh.so",
+ "libwtc9.so"
+ ]
+ GLOBAL_BIN_PATH_EXCLUDES = ["/lib", "/lib32", "/lib64", "/usr/lib",
+ "/usr/lib32", "/usr/lib64"]
+
+
+# NOTE: the try: except: block in this code is not necessary under Python 2.4
+# and higher and can be removed once support for Python 2.3 is no longer needed
+EXTENSION_LOADER_SOURCE = \
+"""
+import imp, os, sys
+
+found = False
+for p in sys.path:
+ if not os.path.isdir(p):
+ continue
+ f = os.path.join(p, "%s")
+ if not os.path.exists(f):
+ continue
+ try:
+ m = imp.load_dynamic(__name__, f)
+ except ImportError:
+ del sys.modules[__name__]
+ raise
+ sys.modules[__name__] = m
+ found = True
+ break
+if not found:
+ del sys.modules[__name__]
+ raise ImportError, "No module named %%s" %% __name__
+"""
+
+
+class Freezer(object):
+
+ def __init__(self, executables, constantsModules = [], includes = [],
+ excludes = [], packages = [], replacePaths = [], compress = None,
+ optimizeFlag = 0, copyDependentFiles = None, initScript = None,
+ base = None, path = None, createLibraryZip = None,
+ appendScriptToExe = None, appendScriptToLibrary = None,
+ targetDir = None, binIncludes = [], binExcludes = [],
+ binPathIncludes = [], binPathExcludes = [], icon = None,
+ includeFiles = []):
+ self.executables = executables
+ self.constantsModules = constantsModules
+ self.includes = includes
+ self.excludes = excludes
+ self.packages = packages
+ self.replacePaths = replacePaths
+ self.compress = compress
+ self.optimizeFlag = optimizeFlag
+ self.copyDependentFiles = copyDependentFiles
+ self.initScript = initScript
+ self.base = base
+ self.path = path
+ self.createLibraryZip = createLibraryZip
+ self.appendScriptToExe = appendScriptToExe
+ self.appendScriptToLibrary = appendScriptToLibrary
+ self.targetDir = targetDir
+ self.binIncludes = [os.path.normcase(n) \
+ for n in GLOBAL_BIN_INCLUDES + binIncludes]
+ self.binExcludes = [os.path.normcase(n) \
+ for n in GLOBAL_BIN_EXCLUDES + binExcludes]
+ self.binPathIncludes = [os.path.normcase(n) for n in binPathIncludes]
+ self.binPathExcludes = [os.path.normcase(n) \
+ for n in GLOBAL_BIN_PATH_EXCLUDES + binPathExcludes]
+ self.icon = icon
+ self.includeFiles = includeFiles
+ self._VerifyConfiguration()
+
+ def _CopyFile(self, source, target, copyDependentFiles,
+ includeMode = False):
+ normalizedSource = os.path.normcase(os.path.normpath(source))
+ normalizedTarget = os.path.normcase(os.path.normpath(target))
+ if normalizedTarget in self.filesCopied:
+ return
+ if normalizedSource == normalizedTarget:
+ return
+ self._RemoveFile(target)
+ targetDir = os.path.dirname(target)
+ self._CreateDirectory(targetDir)
+ print "copying", source, "->", target
+ shutil.copyfile(source, target)
+ if includeMode:
+ shutil.copymode(source, target)
+ self.filesCopied[normalizedTarget] = None
+ if copyDependentFiles:
+ for source in self._GetDependentFiles(source):
+ target = os.path.join(targetDir, os.path.basename(source))
+ self._CopyFile(source, target, copyDependentFiles)
+
+ def _CreateDirectory(self, path):
+ if not os.path.isdir(path):
+ print "creating directory", path
+ os.makedirs(path)
+
+ def _FreezeExecutable(self, exe):
+ if self.createLibraryZip:
+ finder = self.finder
+ else:
+ finder = self._GetModuleFinder(exe)
+ if exe.script is None:
+ scriptModule = None
+ else:
+ scriptModule = finder.IncludeFile(exe.script, exe.moduleName)
+ self._CopyFile(exe.base, exe.targetName, exe.copyDependentFiles,
+ includeMode = True)
+ if exe.icon is not None:
+ if sys.platform == "win32":
+ cx_Freeze.util.AddIcon(exe.targetName, exe.icon)
+ else:
+ targetName = os.path.join(os.path.dirname(exe.targetName),
+ os.path.basename(exe.icon))
+ self._CopyFile(exe.icon, targetName,
+ copyDependentFiles = False)
+ if not os.access(exe.targetName, os.W_OK):
+ mode = os.stat(exe.targetName).st_mode
+ os.chmod(exe.targetName, mode | stat.S_IWUSR)
+ if not exe.appendScriptToLibrary:
+ if exe.appendScriptToExe:
+ fileName = exe.targetName
+ else:
+ baseFileName, ext = os.path.splitext(exe.targetName)
+ fileName = baseFileName + ".zip"
+ self._RemoveFile(fileName)
+ if not self.createLibraryZip and exe.copyDependentFiles:
+ scriptModule = None
+ self._WriteModules(fileName, exe.initScript, finder, exe.compress,
+ exe.copyDependentFiles, scriptModule)
+
+ def _GetBaseFileName(self, argsSource = None):
+ if argsSource is None:
+ argsSource = self
+ name = argsSource.base
+ if name is None:
+ if argsSource.copyDependentFiles:
+ name = "Console"
+ else:
+ name = "ConsoleKeepPath"
+ argsSource.base = self._GetFileName("bases", name)
+ if argsSource.base is None:
+ raise ConfigError("no base named %s", name)
+
+ def _GetDependentFiles(self, path):
+ dependentFiles = self.dependentFiles.get(path)
+ if dependentFiles is None:
+ if sys.platform == "win32":
+ origPath = os.environ["PATH"]
+ os.environ["PATH"] = origPath + os.pathsep + \
+ os.pathsep.join(sys.path)
+ dependentFiles = cx_Freeze.util.GetDependentFiles(path)
+ os.environ["PATH"] = origPath
+ else:
+ dependentFiles = []
+ for line in os.popen('ldd "%s"' % path):
+ parts = line.strip().split(" => ")
+ if len(parts) != 2:
+ continue
+ dependentFile = parts[1]
+ if dependentFile == "not found":
+ print "WARNING: cannot find", parts[0]
+ continue
+ pos = dependentFile.find(" (")
+ if pos >= 0:
+ dependentFile = dependentFile[:pos].strip()
+ if dependentFile:
+ dependentFiles.append(dependentFile)
+ dependentFiles = self.dependentFiles[path] = \
+ [f for f in dependentFiles if self._ShouldCopyFile(f)]
+ return dependentFiles
+
+ def _GetFileName(self, dir, name):
+ if os.path.isabs(name):
+ return name
+ name = os.path.normcase(name)
+ fullDir = os.path.join(os.path.dirname(cx_Freeze.__file__), dir)
+ if os.path.isdir(fullDir):
+ for fileName in os.listdir(fullDir):
+ if name == os.path.splitext(os.path.normcase(fileName))[0]:
+ return os.path.join(fullDir, fileName)
+
+ def _GetInitScriptFileName(self, argsSource = None):
+ if argsSource is None:
+ argsSource = self
+ name = argsSource.initScript
+ if name is None:
+ if argsSource.copyDependentFiles:
+ name = "Console"
+ else:
+ name = "ConsoleKeepPath"
+ argsSource.initScript = self._GetFileName("initscripts", name)
+ if argsSource.initScript is None:
+ raise ConfigError("no initscript named %s", name)
+
+ def _GetModuleFinder(self, argsSource = None):
+ if argsSource is None:
+ argsSource = self
+ finder = cx_Freeze.ModuleFinder(self.includeFiles, argsSource.excludes,
+ argsSource.path, argsSource.replacePaths)
+ if argsSource.copyDependentFiles:
+ finder.IncludeModule("imp")
+ finder.IncludeModule("os")
+ finder.IncludeModule("sys")
+ if argsSource.compress:
+ finder.IncludeModule("zlib")
+ for name in argsSource.includes:
+ finder.IncludeModule(name)
+ for name in argsSource.packages:
+ finder.IncludePackage(name)
+ return finder
+
+ def _PrintReport(self, fileName, modules):
+ print "writing zip file", fileName
+ print
+ print " %-25s %s" % ("Name", "File")
+ print " %-25s %s" % ("----", "----")
+ for module in modules:
+ if module.path:
+ print "P",
+ else:
+ print "m",
+ print "%-25s" % module.name, module.file or ""
+ print
+
+ def _RemoveFile(self, path):
+ if os.path.exists(path):
+ os.chmod(path, 0777)
+ os.remove(path)
+
+ def _ShouldCopyFile(self, path):
+ dir, name = os.path.split(os.path.normcase(path))
+ parts = name.split(".")
+ tweaked = False
+ while True:
+ if not parts[-1].isdigit():
+ break
+ parts.pop(-1)
+ tweaked = True
+ if tweaked:
+ name = ".".join(parts)
+ if name in self.binIncludes:
+ return True
+ if name in self.binExcludes:
+ return False
+ for path in self.binPathIncludes:
+ if dir.startswith(path):
+ return True
+ for path in self.binPathExcludes:
+ if dir.startswith(path):
+ return False
+ return True
+
+ def _VerifyCanAppendToLibrary(self):
+ if not self.createLibraryZip:
+ raise ConfigError("script cannot be appended to library zip if "
+ "one is not being created")
+
+ def _VerifyConfiguration(self):
+ if self.compress is None:
+ self.compress = True
+ if self.copyDependentFiles is None:
+ self.copyDependentFiles = True
+ if self.createLibraryZip is None:
+ self.createLibraryZip = True
+ if self.appendScriptToExe is None:
+ self.appendScriptToExe = False
+ if self.appendScriptToLibrary is None:
+ self.appendScriptToLibrary = \
+ self.createLibraryZip and not self.appendScriptToExe
+ if self.targetDir is None:
+ self.targetDir = os.path.abspath("dist")
+ self._GetInitScriptFileName()
+ self._GetBaseFileName()
+ if self.path is None:
+ self.path = sys.path
+ if self.appendScriptToLibrary:
+ self._VerifyCanAppendToLibrary()
+ for sourceFileName, targetFileName in self.includeFiles:
+ if not os.path.exists(sourceFileName):
+ raise ConfigError("cannot find file/directory named %s",
+ sourceFileName)
+ if os.path.isabs(targetFileName):
+ raise ConfigError("target file/directory cannot be absolute")
+ for executable in self.executables:
+ executable._VerifyConfiguration(self)
+
+ def _WriteModules(self, fileName, initScript, finder, compress,
+ copyDependentFiles, scriptModule = None):
+ initModule = finder.IncludeFile(initScript, "cx_Freeze__init__")
+ if scriptModule is None:
+ for module in self.constantsModules:
+ module.Create(finder)
+ modules = [m for m in finder.modules \
+ if m.name not in self.excludeModules]
+ else:
+ modules = [initModule, scriptModule]
+ self.excludeModules[initModule.name] = None
+ self.excludeModules[scriptModule.name] = None
+ itemsToSort = [(m.name, m) for m in modules]
+ itemsToSort.sort()
+ modules = [m for n, m in itemsToSort]
+ self._PrintReport(fileName, modules)
+ if scriptModule is None:
+ finder.ReportMissingModules()
+ targetDir = os.path.dirname(fileName)
+ self._CreateDirectory(targetDir)
+ filesToCopy = []
+ if os.path.exists(fileName):
+ mode = "a"
+ else:
+ mode = "w"
+ outFile = zipfile.PyZipFile(fileName, mode, zipfile.ZIP_DEFLATED)
+ for module in modules:
+ if module.code is None and module.file is not None:
+ fileName = os.path.basename(module.file)
+ baseFileName, ext = os.path.splitext(fileName)
+ if baseFileName != module.name and module.name != "zlib":
+ if "." in module.name:
+ fileName = module.name + ext
+ generatedFileName = "ExtensionLoader_%s.py" % \
+ module.name.replace(".", "_")
+ module.code = compile(EXTENSION_LOADER_SOURCE % fileName,
+ generatedFileName, "exec")
+ target = os.path.join(targetDir, fileName)
+ filesToCopy.append((module, target))
+ if module.code is None:
+ continue
+ fileName = "/".join(module.name.split("."))
+ if module.path:
+ fileName += "/__init__"
+ if module.file is not None and os.path.exists(module.file):
+ mtime = os.stat(module.file).st_mtime
+ else:
+ mtime = time.time()
+ zipTime = time.localtime(mtime)[:6]
+ data = imp.get_magic() + struct.pack("" % self.script
+
+ def _VerifyConfiguration(self, freezer):
+ if self.path is None:
+ self.path = freezer.path
+ if self.targetDir is None:
+ self.targetDir = freezer.targetDir
+ if self.includes is None:
+ self.includes = freezer.includes
+ if self.excludes is None:
+ self.excludes = freezer.excludes
+ if self.packages is None:
+ self.packages = freezer.packages
+ if self.replacePaths is None:
+ self.replacePaths = freezer.replacePaths
+ if self.compress is None:
+ self.compress = freezer.compress
+ if self.copyDependentFiles is None:
+ self.copyDependentFiles = freezer.copyDependentFiles
+ if self.appendScriptToExe is None:
+ self.appendScriptToExe = freezer.appendScriptToExe
+ if self.appendScriptToLibrary is None:
+ self.appendScriptToLibrary = freezer.appendScriptToLibrary
+ if self.initScript is None:
+ self.initScript = freezer.initScript
+ else:
+ freezer._GetInitScriptFileName(self)
+ if self.base is None:
+ self.base = freezer.base
+ else:
+ freezer._GetBaseFileName(self)
+ if self.appendScriptToLibrary:
+ freezer._VerifyCanAppendToLibrary()
+ if self.icon is None:
+ self.icon = freezer.icon
+ if self.script is not None:
+ name, ext = os.path.splitext(os.path.basename(self.script))
+ if self.appendScriptToLibrary:
+ self.moduleName = "%s__main__" % os.path.normcase(name)
+ else:
+ self.moduleName = "__main__"
+ if self.targetName is None:
+ baseName, ext = os.path.splitext(self.base)
+ self.targetName = name + ext
+ self.targetName = os.path.join(self.targetDir, self.targetName)
+
+
+class ConstantsModule(object):
+
+ def __init__(self, releaseString = None, copyright = None,
+ moduleName = "BUILD_CONSTANTS", timeFormat = "%B %d, %Y %H:%M:%S"):
+ self.moduleName = moduleName
+ self.timeFormat = timeFormat
+ self.values = {}
+ self.values["BUILD_RELEASE_STRING"] = releaseString
+ self.values["BUILD_COPYRIGHT"] = copyright
+
+ def Create(self, finder):
+ """Create the module which consists of declaration statements for each
+ of the values."""
+ today = datetime.datetime.today()
+ sourceTimestamp = 0
+ for module in finder.modules:
+ if module.file is None:
+ continue
+ if module.inZipFile:
+ continue
+ if not os.path.exists(module.file):
+ raise ConfigError("no file named %s", module.file)
+ timestamp = os.stat(module.file).st_mtime
+ sourceTimestamp = max(sourceTimestamp, timestamp)
+ sourceTimestamp = datetime.datetime.fromtimestamp(sourceTimestamp)
+ self.values["BUILD_TIMESTAMP"] = today.strftime(self.timeFormat)
+ self.values["BUILD_HOST"] = socket.gethostname().split(".")[0]
+ self.values["SOURCE_TIMESTAMP"] = \
+ sourceTimestamp.strftime(self.timeFormat)
+ module = finder._AddModule(self.moduleName)
+ sourceParts = []
+ names = self.values.keys()
+ names.sort()
+ for name in names:
+ value = self.values[name]
+ sourceParts.append("%s = %r" % (name, value))
+ source = "\n".join(sourceParts)
+ module.code = compile(source, "%s.py" % self.moduleName, "exec")
+
diff --git a/installer/cx_Freeze/cx_Freeze/hooks.py b/installer/cx_Freeze/cx_Freeze/hooks.py
new file mode 100644
index 0000000000..edc2f78788
--- /dev/null
+++ b/installer/cx_Freeze/cx_Freeze/hooks.py
@@ -0,0 +1,281 @@
+import os
+import sys
+
+def initialize(finder):
+ """upon initialization of the finder, this routine is called to set up some
+ automatic exclusions for various platforms."""
+ finder.ExcludeModule("FCNTL")
+ finder.ExcludeModule("os.path")
+ if os.name == "nt":
+ finder.ExcludeModule("fcntl")
+ finder.ExcludeModule("grp")
+ finder.ExcludeModule("pwd")
+ finder.ExcludeModule("termios")
+ else:
+ finder.ExcludeModule("_winreg")
+ finder.ExcludeModule("msilib")
+ finder.ExcludeModule("msvcrt")
+ finder.ExcludeModule("nt")
+ if os.name not in ("os2", "ce"):
+ finder.ExcludeModule("ntpath")
+ finder.ExcludeModule("nturl2path")
+ finder.ExcludeModule("pythoncom")
+ finder.ExcludeModule("pywintypes")
+ finder.ExcludeModule("winerror")
+ finder.ExcludeModule("winsound")
+ finder.ExcludeModule("win32api")
+ finder.ExcludeModule("win32con")
+ finder.ExcludeModule("win32event")
+ finder.ExcludeModule("win32file")
+ finder.ExcludeModule("win32pdh")
+ finder.ExcludeModule("win32pipe")
+ finder.ExcludeModule("win32process")
+ finder.ExcludeModule("win32security")
+ finder.ExcludeModule("win32service")
+ finder.ExcludeModule("wx.activex")
+ if os.name != "posix":
+ finder.ExcludeModule("posix")
+ if os.name != "mac":
+ finder.ExcludeModule("Carbon")
+ finder.ExcludeModule("gestalt")
+ finder.ExcludeModule("ic")
+ finder.ExcludeModule("mac")
+ finder.ExcludeModule("MacOS")
+ finder.ExcludeModule("macpath")
+ finder.ExcludeModule("macurl2path")
+ if os.name != "nt":
+ finder.ExcludeModule("EasyDialogs")
+ if os.name != "os2":
+ finder.ExcludeModule("os2")
+ finder.ExcludeModule("os2emxpath")
+ finder.ExcludeModule("_emx_link")
+ if os.name != "ce":
+ finder.ExcludeModule("ce")
+ if os.name != "riscos":
+ finder.ExcludeModule("riscos")
+ finder.ExcludeModule("riscosenviron")
+ finder.ExcludeModule("riscospath")
+ finder.ExcludeModule("rourl2path")
+ if sys.platform[:4] != "java":
+ finder.ExcludeModule("java.lang")
+ finder.ExcludeModule("org.python.core")
+
+
+def load_cElementTree(finder, module):
+ """the cElementTree module implicitly loads the elementtree.ElementTree
+ module; make sure this happens."""
+ finder.IncludeModule("elementtree.ElementTree")
+
+
+def load_ceODBC(finder, module):
+ """the ceODBC module implicitly imports both datetime and decimal; make
+ sure this happens."""
+ finder.IncludeModule("datetime")
+ finder.IncludeModule("decimal")
+
+
+def load_cx_Oracle(finder, module):
+ """the cx_Oracle module implicitly imports datetime; make sure this
+ happens."""
+ finder.IncludeModule("datetime")
+
+
+def load_docutils_frontend(finder, module):
+ """The optik module is the old name for the optparse module; ignore the
+ module if it cannot be found."""
+ module.IgnoreName("optik")
+
+
+def load_dummy_threading(finder, module):
+ """the dummy_threading module plays games with the name of the threading
+ module for its own purposes; ignore that here"""
+ finder.ExcludeModule("_dummy_threading")
+
+
+def load_email(finder, module):
+ """the email package has a bunch of aliases as the submodule names were
+ all changed to lowercase in Python 2.5; mimic that here."""
+ if sys.version_info[:2] >= (2, 5):
+ for name in ("Charset", "Encoders", "Errors", "FeedParser",
+ "Generator", "Header", "Iterators", "Message", "Parser",
+ "Utils", "base64MIME", "quopriMIME"):
+ finder.AddAlias("email.%s" % name, "email.%s" % name.lower())
+
+
+def load_ftplib(finder, module):
+ """the ftplib module attempts to import the SOCKS module; ignore this
+ module if it cannot be found"""
+ module.IgnoreName("SOCKS")
+
+
+def load_matplotlib(finder, module):
+ """the matplotlib module requires data to be found in mpl-data in the
+ same directory as the frozen executable so oblige it"""
+ dir = os.path.join(module.path[0], "mpl-data")
+ finder.IncludeFiles(dir, "mpl-data")
+
+
+def load_matplotlib_numerix(finder, module):
+ """the numpy.numerix module loads a number of modules dynamically"""
+ for name in ("ma", "fft", "linear_algebra", "random_array", "mlab"):
+ finder.IncludeModule("%s.%s" % (module.name, name))
+
+
+def load_numpy_linalg(finder, module):
+ """the numpy.linalg module implicitly loads the lapack_lite module; make
+ sure this happens"""
+ finder.IncludeModule("numpy.linalg.lapack_lite")
+
+
+def load_pty(finder, module):
+ """The sgi module is not needed for this module to function."""
+ module.IgnoreName("sgi")
+
+
+def load_pythoncom(finder, module):
+ """the pythoncom module is actually contained in a DLL but since those
+ cannot be loaded directly in Python 2.5 and higher a special module is
+ used to perform that task; simply use that technique directly to
+ determine the name of the DLL and ensure it is included as a normal
+ extension; also load the pywintypes module which is implicitly
+ loaded."""
+ import pythoncom
+ module.file = pythoncom.__file__
+ module.code = None
+ finder.IncludeModule("pywintypes")
+
+
+def load_pywintypes(finder, module):
+ """the pywintypes module is actually contained in a DLL but since those
+ cannot be loaded directly in Python 2.5 and higher a special module is
+ used to perform that task; simply use that technique directly to
+ determine the name of the DLL and ensure it is included as a normal
+ extension."""
+ import pywintypes
+ module.file = pywintypes.__file__
+ module.code = None
+
+
+def load_PyQt4_Qt(finder, module):
+ """the PyQt4.Qt module is an extension module which imports a number of
+ other modules and injects their namespace into its own. It seems a
+ foolish way of doing things but perhaps there is some hidden advantage
+ to this technique over pure Python; ignore the absence of some of
+ the modules since not every installation includes all of them."""
+ finder.IncludeModule("PyQt4.QtCore")
+ finder.IncludeModule("PyQt4.QtGui")
+ finder.IncludeModule("sip")
+ for name in ("PyQt4.QtSvg", "PyQt4.Qsci", "PyQt4.QtAssistant",
+ "PyQt4.QtNetwork", "PyQt4.QtOpenGL", "PyQt4.QtScript", "PyQt4._qt",
+ "PyQt4.QtSql", "PyQt4.QtSvg", "PyQt4.QtTest", "PyQt4.QtXml"):
+ try:
+ finder.IncludeModule(name)
+ except ImportError:
+ pass
+
+
+def load_Tkinter(finder, module):
+ """the Tkinter module has data files that are required to be loaded so
+ ensure that they are copied into the directory that is expected at
+ runtime."""
+ import Tkinter
+ import _tkinter
+ tk = _tkinter.create()
+ tclDir = os.path.dirname(tk.call("info", "library"))
+ tclSourceDir = os.path.join(tclDir, "tcl%s" % _tkinter.TCL_VERSION)
+ tkSourceDir = os.path.join(tclDir, "tk%s" % _tkinter.TK_VERSION)
+ finder.IncludeFiles(tclSourceDir, "tcl")
+ finder.IncludeFiles(tkSourceDir, "tk")
+
+
+def load_tempfile(finder, module):
+ """the tempfile module attempts to load the fcntl and thread modules but
+ continues if these modules cannot be found; ignore these modules if they
+ cannot be found."""
+ module.IgnoreName("fcntl")
+ module.IgnoreName("thread")
+
+
+def load_time(finder, module):
+ """the time module implicitly loads _strptime; make sure this happens."""
+ finder.IncludeModule("_strptime")
+
+
+def load_win32api(finder, module):
+ """the win32api module implicitly loads the pywintypes module; make sure
+ this happens."""
+ finder.IncludeModule("pywintypes")
+
+
+def load_win32com(finder, module):
+ """the win32com package manipulates its search path at runtime to include
+ the sibling directory called win32comext; simulate that by changing the
+ search path in a similar fashion here."""
+ baseDir = os.path.dirname(os.path.dirname(module.file))
+ module.path.append(os.path.join(baseDir, "win32comext"))
+
+
+def load_win32file(finder, module):
+ """the win32api module implicitly loads the pywintypes module; make sure
+ this happens."""
+ finder.IncludeModule("pywintypes")
+
+
+def load_xml(finder, module):
+ """the builtin xml package attempts to load the _xmlplus module to see if
+ that module should take its role instead; ignore the failure to find
+ this module, though."""
+ module.IgnoreName("_xmlplus")
+
+
+def load_xml_etree_cElementTree(finder, module):
+ """the xml.etree.cElementTree module implicitly loads the
+ xml.etree.ElementTree module; make sure this happens."""
+ finder.IncludeModule("xml.etree.ElementTree")
+
+def load_IPython(finder, module):
+ ipy = os.path.join(os.path.dirname(module.file), 'Extensions')
+ extensions = set([])
+ for m in os.listdir(ipy):
+ extensions.add(os.path.splitext(m)[0])
+ extensions.remove('__init__')
+ for m in extensions:
+ finder.IncludeModule('IPython.Extensions.'+m)
+
+def load_lxml(finder, module):
+ finder.IncludeModule('lxml._elementpath')
+
+def load_cherrypy(finder, module):
+ finder.IncludeModule('cherrypy.lib.encoding')
+
+def missing_cElementTree(finder, caller):
+ """the cElementTree has been incorporated into the standard library in
+ Python 2.5 so ignore its absence if it cannot found."""
+ if sys.version_info[:2] >= (2, 5):
+ caller.IgnoreName("cElementTree")
+
+
+def missing_EasyDialogs(finder, caller):
+ """the EasyDialogs module is not normally present on Windows but it also
+ may be so instead of excluding it completely, ignore it if it can't be
+ found"""
+ if sys.platform == "win32":
+ caller.IgnoreName("EasyDialogs")
+
+
+def missing_readline(finder, caller):
+ """the readline module is not normally present on Windows but it also may
+ be so instead of excluding it completely, ignore it if it can't be
+ found"""
+ if sys.platform == "win32":
+ caller.IgnoreName("readline")
+
+
+def missing_xml_etree(finder, caller):
+ """the xml.etree package is new for Python 2.5 but it is common practice
+ to use a try..except.. block in order to support versions earlier than
+ Python 2.5 transparently; ignore the absence of the package in this
+ situation."""
+ if sys.version_info[:2] < (2, 5):
+ caller.IgnoreName("xml.etree")
+
diff --git a/installer/cx_Freeze/cx_Freeze/main.py b/installer/cx_Freeze/cx_Freeze/main.py
new file mode 100644
index 0000000000..1704c598d2
--- /dev/null
+++ b/installer/cx_Freeze/cx_Freeze/main.py
@@ -0,0 +1,171 @@
+import optparse
+import os
+import shutil
+import stat
+import sys
+
+import cx_Freeze
+
+__all__ = ["main"]
+
+USAGE = \
+"""
+%prog [options] [SCRIPT]
+
+Freeze a Python script and all of its referenced modules to a base
+executable which can then be distributed without requiring a Python
+installation."""
+
+VERSION = \
+"""
+%%prog %s
+Copyright (c) 2007-2008 Colt Engineering. All rights reserved.
+Copyright (c) 2001-2006 Computronix Corporation. All rights reserved.""" % \
+ cx_Freeze.version
+
+
+def ParseCommandLine():
+ parser = optparse.OptionParser(version = VERSION.strip(),
+ usage = USAGE.strip())
+ parser.add_option("-O",
+ action = "count",
+ default = 0,
+ dest = "optimized",
+ help = "optimize generated bytecode as per PYTHONOPTIMIZE; "
+ "use -OO in order to remove doc strings")
+ parser.add_option("-c", "--compress",
+ action = "store_true",
+ dest = "compress",
+ help = "compress byte code in zip files")
+ parser.add_option("--base-name",
+ dest = "baseName",
+ metavar = "NAME",
+ help = "file on which to base the target file; if the name of the "
+ "file is not an absolute file name, the subdirectory bases "
+ "(rooted in the directory in which the freezer is found) "
+ "will be searched for a file matching the name")
+ parser.add_option("--init-script",
+ dest = "initScript",
+ metavar = "NAME",
+ help = "script which will be executed upon startup; if the name "
+ "of the file is not an absolute file name, the "
+ "subdirectory initscripts (rooted in the directory in "
+ "which the cx_Freeze package is found) will be searched "
+ "for a file matching the name")
+ parser.add_option("--target-dir", "--install-dir",
+ dest = "targetDir",
+ metavar = "DIR",
+ help = "the directory in which to place the target file and "
+ "any dependent files")
+ parser.add_option("--target-name",
+ dest = "targetName",
+ metavar = "NAME",
+ help = "the name of the file to create instead of the base name "
+ "of the script and the extension of the base binary")
+ parser.add_option("--no-copy-deps",
+ dest = "copyDeps",
+ default = True,
+ action = "store_false",
+ help = "do not copy the dependent files (extensions, shared "
+ "libraries, etc.) to the target directory; this also "
+ "modifies the default init script to ConsoleKeepPath.py "
+ "and means that the target executable requires a Python "
+ "installation to execute properly")
+ parser.add_option("--default-path",
+ action = "append",
+ dest = "defaultPath",
+ metavar = "DIRS",
+ help = "list of paths separated by the standard path separator "
+ "for the platform which will be used to initialize "
+ "sys.path prior to running the module finder")
+ parser.add_option("--include-path",
+ action = "append",
+ dest = "includePath",
+ metavar = "DIRS",
+ help = "list of paths separated by the standard path separator "
+ "for the platform which will be used to modify sys.path "
+ "prior to running the module finder")
+ parser.add_option("--replace-paths",
+ dest = "replacePaths",
+ metavar = "DIRECTIVES",
+ help = "replace all the paths in modules found in the given paths "
+ "with the given replacement string; multiple values are "
+ "separated by the standard path separator and each value "
+ "is of the form path=replacement_string; path can be * "
+ "which means all paths not already specified")
+ parser.add_option("--include-modules",
+ dest = "includeModules",
+ metavar = "NAMES",
+ help = "comma separated list of modules to include")
+ parser.add_option("--exclude-modules",
+ dest = "excludeModules",
+ metavar = "NAMES",
+ help = "comma separated list of modules to exclude")
+ parser.add_option("--ext-list-file",
+ dest = "extListFile",
+ metavar = "NAME",
+ help = "name of file in which to place the list of dependent files "
+ "which were copied into the target directory")
+ parser.add_option("-z", "--zip-include",
+ dest = "zipIncludes",
+ action = "append",
+ default = [],
+ metavar = "SPEC",
+ help = "name of file to add to the zip file or a specification of "
+ "the form name=arcname which will specify the archive name "
+ "to use; multiple --zip-include arguments can be used")
+ options, args = parser.parse_args()
+ if len(args) == 0:
+ options.script = None
+ elif len(args) == 1:
+ options.script, = args
+ else:
+ parser.error("only one script can be specified")
+ if not args and options.includeModules is None and options.copyDeps:
+ parser.error("script or a list of modules must be specified")
+ if not args and options.targetName is None:
+ parser.error("script or a target name must be specified")
+ if options.excludeModules:
+ options.excludeModules = options.excludeModules.split(",")
+ else:
+ options.excludeModules = []
+ if options.includeModules:
+ options.includeModules = options.includeModules.split(",")
+ else:
+ options.includeModules = []
+ replacePaths = []
+ if options.replacePaths:
+ for directive in options.replacePaths.split(os.pathsep):
+ fromPath, replacement = directive.split("=")
+ replacePaths.append((fromPath, replacement))
+ options.replacePaths = replacePaths
+ if options.defaultPath is not None:
+ sys.path = [p for mp in options.defaultPath \
+ for p in mp.split(os.pathsep)]
+ if options.includePath is not None:
+ paths = [p for mp in options.includePath for p in mp.split(os.pathsep)]
+ sys.path = paths + sys.path
+ if options.script is not None:
+ sys.path.insert(0, os.path.dirname(options.script))
+ return options
+
+
+def main():
+ options = ParseCommandLine()
+ executables = [cx_Freeze.Executable(options.script,
+ targetName = options.targetName)]
+ freezer = cx_Freeze.Freezer(executables,
+ includes = options.includeModules,
+ excludes = options.excludeModules,
+ replacePaths = options.replacePaths,
+ compress = options.compress,
+ optimizeFlag = options.optimized,
+ copyDependentFiles = options.copyDeps,
+ initScript = options.initScript,
+ base = options.baseName,
+ path = None,
+ createLibraryZip = False,
+ appendScriptToExe = True,
+ targetDir = options.targetDir)
+ freezer.Freeze()
+
diff --git a/installer/cx_Freeze/cx_Freeze/windist.py b/installer/cx_Freeze/cx_Freeze/windist.py
new file mode 100644
index 0000000000..51af544771
--- /dev/null
+++ b/installer/cx_Freeze/cx_Freeze/windist.py
@@ -0,0 +1,337 @@
+import distutils.command.bdist_msi
+import msilib
+import os
+
+__all__ = [ "bdist_msi" ]
+
+# force the remove existing products action to happen first since Windows
+# installer appears to be braindead and doesn't handle files shared between
+# different "products" very well
+sequence = msilib.sequence.InstallExecuteSequence
+for index, info in enumerate(sequence):
+ if info[0] == u'RemoveExistingProducts':
+ sequence[index] = (info[0], info[1], 1450)
+
+
+class bdist_msi(distutils.command.bdist_msi.bdist_msi):
+ user_options = distutils.command.bdist_msi.bdist_msi.user_options + [
+ ('add-to-path=', None, 'add target dir to PATH environment variable'),
+ ('upgrade-code=', None, 'upgrade code to use')
+ ]
+ x = y = 50
+ width = 370
+ height = 300
+ title = "[ProductName] Setup"
+ modeless = 1
+ modal = 3
+
+ def add_config(self, fullname):
+ initialTargetDir = self.get_initial_target_dir(fullname)
+ if self.add_to_path is None:
+ self.add_to_path = False
+ for executable in self.distribution.executables:
+ if os.path.basename(executable.base).startswith("Console"):
+ self.add_to_path = True
+ break
+ if self.add_to_path:
+ msilib.add_data(self.db, 'Environment',
+ [("E_PATH", "Path", r"[~];[TARGETDIR]", "TARGETDIR")])
+ msilib.add_data(self.db, 'CustomAction',
+ [("InitialTargetDir", 256 + 51, "TARGETDIR", initialTargetDir)
+ ])
+ msilib.add_data(self.db, 'InstallExecuteSequence',
+ [("InitialTargetDir", 'TARGETDIR=""', 401)])
+ msilib.add_data(self.db, 'InstallUISequence',
+ [("PrepareDlg", None, 140),
+ ("InitialTargetDir", 'TARGETDIR=""', 401),
+ ("SelectDirectoryDlg", "not Installed", 1230),
+ ("MaintenanceTypeDlg",
+ "Installed and not Resume and not Preselected", 1250),
+ ("ProgressDlg", None, 1280)
+ ])
+
+ def add_cancel_dialog(self):
+ dialog = msilib.Dialog(self.db, "CancelDlg", 50, 10, 260, 85, 3,
+ self.title, "No", "No", "No")
+ dialog.text("Text", 48, 15, 194, 30, 3,
+ "Are you sure you want to cancel [ProductName] installation?")
+ button = dialog.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No")
+ button.event("EndDialog", "Exit")
+ button = dialog.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes")
+ button.event("EndDialog", "Return")
+
+ def add_error_dialog(self):
+ dialog = msilib.Dialog(self.db, "ErrorDlg", 50, 10, 330, 101, 65543,
+ self.title, "ErrorText", None, None)
+ dialog.text("ErrorText", 50, 9, 280, 48, 3, "")
+ for text, x in [("No", 120), ("Yes", 240), ("Abort", 0),
+ ("Cancel", 42), ("Ignore", 81), ("Ok", 159), ("Retry", 198)]:
+ button = dialog.pushbutton(text[0], x, 72, 81, 21, 3, text, None)
+ button.event("EndDialog", "Error%s" % text)
+
+ def add_exit_dialog(self):
+ dialog = distutils.command.bdist_msi.PyDialog(self.db, "ExitDialog",
+ self.x, self.y, self.width, self.height, self.modal,
+ self.title, "Finish", "Finish", "Finish")
+ dialog.title("Completing the [ProductName] installer")
+ dialog.back("< Back", "Finish", active = False)
+ dialog.cancel("Cancel", "Back", active = False)
+ dialog.text("Description", 15, 235, 320, 20, 0x30003,
+ "Click the Finish button to exit the installer.")
+ button = dialog.next("Finish", "Cancel", name = "Finish")
+ button.event("EndDialog", "Return")
+
+ def add_fatal_error_dialog(self):
+ dialog = distutils.command.bdist_msi.PyDialog(self.db, "FatalError",
+ self.x, self.y, self.width, self.height, self.modal,
+ self.title, "Finish", "Finish", "Finish")
+ dialog.title("[ProductName] installer ended prematurely")
+ dialog.back("< Back", "Finish", active = False)
+ dialog.cancel("Cancel", "Back", active = False)
+ dialog.text("Description1", 15, 70, 320, 80, 0x30003,
+ "[ProductName] setup ended prematurely because of an error. "
+ "Your system has not been modified. To install this program "
+ "at a later time, please run the installation again.")
+ dialog.text("Description2", 15, 155, 320, 20, 0x30003,
+ "Click the Finish button to exit the installer.")
+ button = dialog.next("Finish", "Cancel", name = "Finish")
+ button.event("EndDialog", "Exit")
+
+ def add_files_in_use_dialog(self):
+ dialog = distutils.command.bdist_msi.PyDialog(self.db, "FilesInUse",
+ self.x, self.y, self.width, self.height, 19, self.title,
+ "Retry", "Retry", "Retry", bitmap = False)
+ dialog.text("Title", 15, 6, 200, 15, 0x30003,
+ r"{\DlgFontBold8}Files in Use")
+ dialog.text("Description", 20, 23, 280, 20, 0x30003,
+ "Some files that need to be updated are currently in use.")
+ dialog.text("Text", 20, 55, 330, 50, 3,
+ "The following applications are using files that need to be "
+ "updated by this setup. Close these applications and then "
+ "click Retry to continue the installation or Cancel to exit "
+ "it.")
+ dialog.control("List", "ListBox", 20, 107, 330, 130, 7,
+ "FileInUseProcess", None, None, None)
+ button = dialog.back("Exit", "Ignore", name = "Exit")
+ button.event("EndDialog", "Exit")
+ button = dialog.next("Ignore", "Retry", name = "Ignore")
+ button.event("EndDialog", "Ignore")
+ button = dialog.cancel("Retry", "Exit", name = "Retry")
+ button.event("EndDialog", "Retry")
+
+ def add_maintenance_type_dialog(self):
+ dialog = distutils.command.bdist_msi.PyDialog(self.db,
+ "MaintenanceTypeDlg", self.x, self.y, self.width, self.height,
+ self.modal, self.title, "Next", "Next", "Cancel")
+ dialog.title("Welcome to the [ProductName] Setup Wizard")
+ dialog.text("BodyText", 15, 63, 330, 42, 3,
+ "Select whether you want to repair or remove [ProductName].")
+ group = dialog.radiogroup("RepairRadioGroup", 15, 108, 330, 60, 3,
+ "MaintenanceForm_Action", "", "Next")
+ group.add("Repair", 0, 18, 300, 17, "&Repair [ProductName]")
+ group.add("Remove", 0, 36, 300, 17, "Re&move [ProductName]")
+ dialog.back("< Back", None, active = False)
+ button = dialog.next("Finish", "Cancel")
+ button.event("[REINSTALL]", "ALL",
+ 'MaintenanceForm_Action="Repair"', 5)
+ button.event("[Progress1]", "Repairing",
+ 'MaintenanceForm_Action="Repair"', 6)
+ button.event("[Progress2]", "repairs",
+ 'MaintenanceForm_Action="Repair"', 7)
+ button.event("Reinstall", "ALL",
+ 'MaintenanceForm_Action="Repair"', 8)
+ button.event("[REMOVE]", "ALL",
+ 'MaintenanceForm_Action="Remove"', 11)
+ button.event("[Progress1]", "Removing",
+ 'MaintenanceForm_Action="Remove"', 12)
+ button.event("[Progress2]", "removes",
+ 'MaintenanceForm_Action="Remove"', 13)
+ button.event("Remove", "ALL",
+ 'MaintenanceForm_Action="Remove"', 14)
+ button.event("EndDialog", "Return",
+ 'MaintenanceForm_Action<>"Change"', 20)
+ button = dialog.cancel("Cancel", "RepairRadioGroup")
+ button.event("SpawnDialog", "CancelDlg")
+
+ def add_prepare_dialog(self):
+ dialog = distutils.command.bdist_msi.PyDialog(self.db, "PrepareDlg",
+ self.x, self.y, self.width, self.height, self.modeless,
+ self.title, "Cancel", "Cancel", "Cancel")
+ dialog.text("Description", 15, 70, 320, 40, 0x30003,
+ "Please wait while the installer prepares to guide you through"
+ "the installation.")
+ dialog.title("Welcome to the [ProductName] installer")
+ text = dialog.text("ActionText", 15, 110, 320, 20, 0x30003,
+ "Pondering...")
+ text.mapping("ActionText", "Text")
+ text = dialog.text("ActionData", 15, 135, 320, 30, 0x30003, None)
+ text.mapping("ActionData", "Text")
+ dialog.back("Back", None, active = False)
+ dialog.next("Next", None, active = False)
+ button = dialog.cancel("Cancel", None)
+ button.event("SpawnDialog", "CancelDlg")
+
+ def add_progress_dialog(self):
+ dialog = distutils.command.bdist_msi.PyDialog(self.db, "ProgressDlg",
+ self.x, self.y, self.width, self.height, self.modeless,
+ self.title, "Cancel", "Cancel", "Cancel", bitmap = False)
+ dialog.text("Title", 20, 15, 200, 15, 0x30003,
+ r"{\DlgFontBold8}[Progress1] [ProductName]")
+ dialog.text("Text", 35, 65, 300, 30, 3,
+ "Please wait while the installer [Progress2] [ProductName].")
+ dialog.text("StatusLabel", 35, 100 ,35, 20, 3, "Status:")
+ text = dialog.text("ActionText", 70, 100, self.width - 70, 20, 3,
+ "Pondering...")
+ text.mapping("ActionText", "Text")
+ control = dialog.control("ProgressBar", "ProgressBar", 35, 120, 300,
+ 10, 65537, None, "Progress done", None, None)
+ control.mapping("SetProgress", "Progress")
+ dialog.back("< Back", "Next", active = False)
+ dialog.next("Next >", "Cancel", active = False)
+ button = dialog.cancel("Cancel", "Back")
+ button.event("SpawnDialog", "CancelDlg")
+
+ def add_properties(self):
+ metadata = self.distribution.metadata
+ props = [
+ ('DistVersion', metadata.get_version()),
+ ('DefaultUIFont', 'DlgFont8'),
+ ('ErrorDialog', 'ErrorDlg'),
+ ('Progress1', 'Install'),
+ ('Progress2', 'installs'),
+ ('MaintenanceForm_Action', 'Repair')
+ ]
+ email = metadata.author_email or metadata.maintainer_email
+ if email:
+ props.append(("ARPCONTACT", email))
+ if metadata.url:
+ props.append(("ARPURLINFOABOUT", metadata.url))
+ if self.upgrade_code is not None:
+ props.append(("UpgradeCode", self.upgrade_code))
+ msilib.add_data(self.db, 'Property', props)
+
+ def add_select_directory_dialog(self):
+ dialog = distutils.command.bdist_msi.PyDialog(self.db,
+ "SelectDirectoryDlg", self.x, self.y, self.width, self.height,
+ self.modal, self.title, "Next", "Next", "Cancel")
+ dialog.title("Select destination directory")
+ dialog.back("< Back", None, active = False)
+ button = dialog.next("Next >", "Cancel")
+ button.event("SetTargetPath", "TARGETDIR", ordering = 1)
+ button.event("SpawnWaitDialog", "WaitForCostingDlg", ordering = 2)
+ button.event("EndDialog", "Return", ordering = 3)
+ button = dialog.cancel("Cancel", "DirectoryCombo")
+ button.event("SpawnDialog", "CancelDlg")
+ dialog.control("DirectoryCombo", "DirectoryCombo", 15, 70, 272, 80,
+ 393219, "TARGETDIR", None, "DirectoryList", None)
+ dialog.control("DirectoryList", "DirectoryList", 15, 90, 308, 136, 3,
+ "TARGETDIR", None, "PathEdit", None)
+ dialog.control("PathEdit", "PathEdit", 15, 230, 306, 16, 3,
+ "TARGETDIR", None, "Next", None)
+ button = dialog.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None)
+ button.event("DirectoryListUp", "0")
+ button = dialog.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None)
+ button.event("DirectoryListNew", "0")
+
+ def add_text_styles(self):
+ msilib.add_data(self.db, 'TextStyle',
+ [("DlgFont8", "Tahoma", 9, None, 0),
+ ("DlgFontBold8", "Tahoma", 8, None, 1),
+ ("VerdanaBold10", "Verdana", 10, None, 1),
+ ("VerdanaRed9", "Verdana", 9, 255, 0)
+ ])
+
+ def add_ui(self):
+ self.add_text_styles()
+ self.add_error_dialog()
+ self.add_fatal_error_dialog()
+ self.add_cancel_dialog()
+ self.add_exit_dialog()
+ self.add_user_exit_dialog()
+ self.add_files_in_use_dialog()
+ self.add_wait_for_costing_dialog()
+ self.add_prepare_dialog()
+ self.add_select_directory_dialog()
+ self.add_progress_dialog()
+ self.add_maintenance_type_dialog()
+
+ def add_upgrade_config(self, sversion):
+ if self.upgrade_code is not None:
+ msilib.add_data(self.db, 'Upgrade',
+ [(self.upgrade_code, None, sversion, None, 513, None,
+ "REMOVEOLDVERSION"),
+ (self.upgrade_code, sversion, None, None, 257, None,
+ "REMOVENEWVERSION")
+ ])
+
+ def add_user_exit_dialog(self):
+ dialog = distutils.command.bdist_msi.PyDialog(self.db, "UserExit",
+ self.x, self.y, self.width, self.height, self.modal,
+ self.title, "Finish", "Finish", "Finish")
+ dialog.title("[ProductName] installer was interrupted")
+ dialog.back("< Back", "Finish", active = False)
+ dialog.cancel("Cancel", "Back", active = False)
+ dialog.text("Description1", 15, 70, 320, 80, 0x30003,
+ "[ProductName] setup was interrupted. Your system has not "
+ "been modified. To install this program at a later time, "
+ "please run the installation again.")
+ dialog.text("Description2", 15, 155, 320, 20, 0x30003,
+ "Click the Finish button to exit the installer.")
+ button = dialog.next("Finish", "Cancel", name = "Finish")
+ button.event("EndDialog", "Exit")
+
+ def add_wait_for_costing_dialog(self):
+ dialog = msilib.Dialog(self.db, "WaitForCostingDlg", 50, 10, 260, 85,
+ self.modal, self.title, "Return", "Return", "Return")
+ dialog.text("Text", 48, 15, 194, 30, 3,
+ "Please wait while the installer finishes determining your "
+ "disk space requirements.")
+ button = dialog.pushbutton("Return", 102, 57, 56, 17, 3, "Return",
+ None)
+ button.event("EndDialog", "Exit")
+
+ def get_initial_target_dir(self, fullname):
+ return r"[ProgramFilesFolder]\%s" % fullname
+
+ def get_installer_filename(self, fullname):
+ return os.path.join(self.dist_dir, "%s.msi" % fullname)
+
+ def initialize_options(self):
+ distutils.command.bdist_msi.bdist_msi.initialize_options(self)
+ self.upgrade_code = None
+ self.add_to_path = None
+
+ def run(self):
+ if not self.skip_build:
+ self.run_command('build')
+ install = self.reinitialize_command('install', reinit_subcommands = 1)
+ install.prefix = self.bdist_dir
+ install.skip_build = self.skip_build
+ install.warn_dir = 0
+ distutils.log.info("installing to %s", self.bdist_dir)
+ install.ensure_finalized()
+ install.run()
+ self.mkpath(self.dist_dir)
+ fullname = self.distribution.get_fullname()
+ filename = os.path.abspath(self.get_installer_filename(fullname))
+ if os.path.exists(filename):
+ os.unlink(filename)
+ metadata = self.distribution.metadata
+ author = metadata.author or metadata.maintainer or "UNKNOWN"
+ version = metadata.get_version()
+ sversion = "%d.%d.%d" % \
+ distutils.version.StrictVersion(version).version
+ self.db = msilib.init_database(filename, msilib.schema,
+ self.distribution.metadata.name, msilib.gen_uuid(), sversion,
+ author)
+ msilib.add_tables(self.db, msilib.sequence)
+ self.add_properties()
+ self.add_config(fullname)
+ self.add_upgrade_config(sversion)
+ self.add_ui()
+ self.add_files()
+ self.db.Commit()
+ if not self.keep_temp:
+ distutils.dir_util.remove_tree(self.bdist_dir,
+ dry_run = self.dry_run)
+
diff --git a/installer/cx_Freeze/cxfreeze b/installer/cx_Freeze/cxfreeze
new file mode 100755
index 0000000000..acd6789833
--- /dev/null
+++ b/installer/cx_Freeze/cxfreeze
@@ -0,0 +1,6 @@
+#!/usr/bin/python
+
+from cx_Freeze import main
+
+main()
+
diff --git a/installer/cx_Freeze/initscripts/Console.py b/installer/cx_Freeze/initscripts/Console.py
new file mode 100755
index 0000000000..e10649d722
--- /dev/null
+++ b/installer/cx_Freeze/initscripts/Console.py
@@ -0,0 +1,35 @@
+#------------------------------------------------------------------------------
+# Console.py
+# Initialization script for cx_Freeze which manipulates the path so that the
+# directory in which the executable is found is searched for extensions but
+# no other directory is searched. It also sets the attribute sys.frozen so that
+# the Win32 extensions behave as expected.
+#------------------------------------------------------------------------------
+
+import encodings
+import os
+import sys
+import warnings
+import zipimport
+
+sys.frozen = True
+sys.path = sys.path[:4]
+
+os.environ["TCL_LIBRARY"] = os.path.join(DIR_NAME, "tcl")
+os.environ["TK_LIBRARY"] = os.path.join(DIR_NAME, "tk")
+
+m = __import__("__main__")
+importer = zipimport.zipimporter(INITSCRIPT_ZIP_FILE_NAME)
+if INITSCRIPT_ZIP_FILE_NAME != SHARED_ZIP_FILE_NAME:
+ moduleName = m.__name__
+else:
+ name, ext = os.path.splitext(os.path.basename(os.path.normcase(FILE_NAME)))
+ moduleName = "%s__main__" % name
+code = importer.get_code(moduleName)
+exec code in m.__dict__
+
+if sys.version_info[:2] >= (2, 5):
+ module = sys.modules.get("threading")
+ if module is not None:
+ module._shutdown()
+
diff --git a/installer/cx_Freeze/initscripts/ConsoleKeepPath.py b/installer/cx_Freeze/initscripts/ConsoleKeepPath.py
new file mode 100755
index 0000000000..60151a1ff6
--- /dev/null
+++ b/installer/cx_Freeze/initscripts/ConsoleKeepPath.py
@@ -0,0 +1,19 @@
+#------------------------------------------------------------------------------
+# ConsoleKeepPath.py
+# Initialization script for cx_Freeze which leaves the path alone and does
+# not set the sys.frozen attribute.
+#------------------------------------------------------------------------------
+
+import sys
+import zipimport
+
+m = __import__("__main__")
+importer = zipimport.zipimporter(INITSCRIPT_ZIP_FILE_NAME)
+code = importer.get_code(m.__name__)
+exec code in m.__dict__
+
+if sys.version_info[:2] >= (2, 5):
+ module = sys.modules.get("threading")
+ if module is not None:
+ module._shutdown()
+
diff --git a/installer/cx_Freeze/initscripts/ConsoleSetLibPath.py b/installer/cx_Freeze/initscripts/ConsoleSetLibPath.py
new file mode 100755
index 0000000000..b558652c0a
--- /dev/null
+++ b/installer/cx_Freeze/initscripts/ConsoleSetLibPath.py
@@ -0,0 +1,38 @@
+#------------------------------------------------------------------------------
+# ConsoleSetLibPath.py
+# Initialization script for cx_Freeze which manipulates the path so that the
+# directory in which the executable is found is searched for extensions but
+# no other directory is searched. The environment variable LD_LIBRARY_PATH is
+# manipulated first, however, to ensure that shared libraries found in the
+# target directory are found. This requires a restart of the executable because
+# the environment variable LD_LIBRARY_PATH is only checked at startup.
+#------------------------------------------------------------------------------
+
+import encodings
+import os
+import sys
+import warnings
+import zipimport
+
+paths = os.environ.get("LD_LIBRARY_PATH", "").split(os.pathsep)
+if DIR_NAME not in paths:
+ paths.insert(0, DIR_NAME)
+ os.environ["LD_LIBRARY_PATH"] = os.pathsep.join(paths)
+ os.execv(sys.executable, sys.argv)
+
+sys.frozen = True
+sys.path = sys.path[:4]
+
+os.environ["TCL_LIBRARY"] = os.path.join(DIR_NAME, "tcl")
+os.environ["TK_LIBRARY"] = os.path.join(DIR_NAME, "tk")
+
+m = __import__("__main__")
+importer = zipimport.zipimporter(INITSCRIPT_ZIP_FILE_NAME)
+code = importer.get_code(m.__name__)
+exec code in m.__dict__
+
+if sys.version_info[:2] >= (2, 5):
+ module = sys.modules.get("threading")
+ if module is not None:
+ module._shutdown()
+
diff --git a/installer/cx_Freeze/initscripts/SharedLib.py b/installer/cx_Freeze/initscripts/SharedLib.py
new file mode 100755
index 0000000000..0445367010
--- /dev/null
+++ b/installer/cx_Freeze/initscripts/SharedLib.py
@@ -0,0 +1,20 @@
+#------------------------------------------------------------------------------
+# SharedLib.py
+# Initialization script for cx_Freeze which behaves similarly to the one for
+# console based applications but must handle the case where Python has already
+# been initialized and another DLL of this kind has been loaded. As such it
+# does not block the path unless sys.frozen is not already set.
+#------------------------------------------------------------------------------
+
+import encodings
+import os
+import sys
+import warnings
+
+if not hasattr(sys, "frozen"):
+ sys.frozen = True
+ sys.path = sys.path[:4]
+
+os.environ["TCL_LIBRARY"] = os.path.join(DIR_NAME, "tcl")
+os.environ["TK_LIBRARY"] = os.path.join(DIR_NAME, "tk")
+
diff --git a/installer/cx_Freeze/initscripts/SharedLibSource.py b/installer/cx_Freeze/initscripts/SharedLibSource.py
new file mode 100755
index 0000000000..3edae93694
--- /dev/null
+++ b/installer/cx_Freeze/initscripts/SharedLibSource.py
@@ -0,0 +1,23 @@
+#------------------------------------------------------------------------------
+# SharedLibSource.py
+# Initialization script for cx_Freeze which imports the site module (as per
+# normal processing of a Python script) and then searches for a file with the
+# same name as the shared library but with the extension .pth. The entries in
+# this file are used to modify the path to use for subsequent imports.
+#------------------------------------------------------------------------------
+
+import os
+import sys
+import warnings
+
+# the site module must be imported for normal behavior to take place; it is
+# done dynamically so that cx_Freeze will not add all modules referenced by
+# the site module to the frozen executable
+__import__("site")
+
+# now locate the pth file to modify the path appropriately
+baseName, ext = os.path.splitext(FILE_NAME)
+pathFileName = baseName + ".pth"
+sys.path = [s.strip() for s in file(pathFileName).read().splitlines()] + \
+ sys.path
+
diff --git a/installer/cx_Freeze/samples/advanced/advanced_1.py b/installer/cx_Freeze/samples/advanced/advanced_1.py
new file mode 100644
index 0000000000..2f1b68bceb
--- /dev/null
+++ b/installer/cx_Freeze/samples/advanced/advanced_1.py
@@ -0,0 +1,7 @@
+import sys
+
+print "Hello from cx_Freeze Advanced #1"
+print
+
+module = __import__("testfreeze_1")
+
diff --git a/installer/cx_Freeze/samples/advanced/advanced_2.py b/installer/cx_Freeze/samples/advanced/advanced_2.py
new file mode 100644
index 0000000000..1a6fe37e62
--- /dev/null
+++ b/installer/cx_Freeze/samples/advanced/advanced_2.py
@@ -0,0 +1,7 @@
+import sys
+
+print "Hello from cx_Freeze Advanced #2"
+print
+
+module = __import__("testfreeze_2")
+
diff --git a/installer/cx_Freeze/samples/advanced/modules/testfreeze_1.py b/installer/cx_Freeze/samples/advanced/modules/testfreeze_1.py
new file mode 100644
index 0000000000..6157b72a69
--- /dev/null
+++ b/installer/cx_Freeze/samples/advanced/modules/testfreeze_1.py
@@ -0,0 +1 @@
+print "Test freeze module #1"
diff --git a/installer/cx_Freeze/samples/advanced/modules/testfreeze_2.py b/installer/cx_Freeze/samples/advanced/modules/testfreeze_2.py
new file mode 100644
index 0000000000..ca133a7d58
--- /dev/null
+++ b/installer/cx_Freeze/samples/advanced/modules/testfreeze_2.py
@@ -0,0 +1 @@
+print "Test freeze module #2"
diff --git a/installer/cx_Freeze/samples/advanced/setup.py b/installer/cx_Freeze/samples/advanced/setup.py
new file mode 100644
index 0000000000..3a79cf23af
--- /dev/null
+++ b/installer/cx_Freeze/samples/advanced/setup.py
@@ -0,0 +1,31 @@
+# An advanced setup script to create multiple executables and demonstrate a few
+# of the features available to setup scripts
+#
+# hello.py is a very simple "Hello, world" type script which also displays the
+# environment in which the script runs
+#
+# Run the build process by running the command 'python setup.py build'
+#
+# If everything works well you should find a subdirectory in the build
+# subdirectory that contains the files needed to run the script without Python
+
+import sys
+from cx_Freeze import setup, Executable
+
+executables = [
+ Executable("advanced_1.py"),
+ Executable("advanced_2.py")
+]
+
+buildOptions = dict(
+ compressed = True,
+ includes = ["testfreeze_1", "testfreeze_2"],
+ path = sys.path + ["modules"])
+
+setup(
+ name = "advanced_cx_Freeze_sample",
+ version = "0.1",
+ description = "Advanced sample cx_Freeze script",
+ options = dict(build_exe = buildOptions),
+ executables = executables)
+
diff --git a/installer/cx_Freeze/samples/matplotlib/setup.py b/installer/cx_Freeze/samples/matplotlib/setup.py
new file mode 100644
index 0000000000..54bd97fc3f
--- /dev/null
+++ b/installer/cx_Freeze/samples/matplotlib/setup.py
@@ -0,0 +1,27 @@
+# A simple setup script to create an executable using matplotlib.
+#
+# test_matplotlib.py is a very simple matplotlib application that demonstrates
+# its use.
+#
+# Run the build process by running the command 'python setup.py build'
+#
+# If everything works well you should find a subdirectory in the build
+# subdirectory that contains the files needed to run the application
+
+import cx_Freeze
+import sys
+
+base = None
+if sys.platform == "win32":
+ base = "Win32GUI"
+
+executables = [
+ cx_Freeze.Executable("test_matplotlib.py", base = base)
+]
+
+cx_Freeze.setup(
+ name = "test_matplotlib",
+ version = "0.1",
+ description = "Sample matplotlib script",
+ executables = executables)
+
diff --git a/installer/cx_Freeze/samples/matplotlib/test_matplotlib.py b/installer/cx_Freeze/samples/matplotlib/test_matplotlib.py
new file mode 100644
index 0000000000..2029845ca5
--- /dev/null
+++ b/installer/cx_Freeze/samples/matplotlib/test_matplotlib.py
@@ -0,0 +1,48 @@
+from numpy import arange, sin, pi
+import matplotlib
+matplotlib.use('WXAgg')
+from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
+from matplotlib.backends.backend_wx import NavigationToolbar2Wx
+from matplotlib.figure import Figure
+from wx import *
+
+class CanvasFrame(Frame):
+ def __init__(self):
+ Frame.__init__(self,None,-1, 'CanvasFrame',size=(550,350))
+ self.SetBackgroundColour(NamedColor("WHITE"))
+ self.figure = Figure()
+ self.axes = self.figure.add_subplot(111)
+ t = arange(0.0,3.0,0.01)
+ s = sin(2*pi*t)
+ self.axes.plot(t,s)
+ self.canvas = FigureCanvas(self, -1, self.figure)
+ self.sizer = BoxSizer(VERTICAL)
+ self.sizer.Add(self.canvas, 1, LEFT | TOP | GROW)
+ self.SetSizerAndFit(self.sizer)
+ self.add_toolbar()
+
+ def add_toolbar(self):
+ self.toolbar = NavigationToolbar2Wx(self.canvas)
+ self.toolbar.Realize()
+ if Platform == '__WXMAC__':
+ self.SetToolBar(self.toolbar)
+ else:
+ tw, th = self.toolbar.GetSizeTuple()
+ fw, fh = self.canvas.GetSizeTuple()
+ self.toolbar.SetSize(Size(fw, th))
+ self.sizer.Add(self.toolbar, 0, LEFT | EXPAND)
+ self.toolbar.update()
+
+ def OnPaint(self, event):
+ self.canvas.draw()
+
+class App(App):
+ def OnInit(self):
+ 'Create the main window and insert the custom frame'
+ frame = CanvasFrame()
+ frame.Show(True)
+ return True
+
+app = App(0)
+app.MainLoop()
+
diff --git a/installer/cx_Freeze/samples/relimport/pkg1/__init__.py b/installer/cx_Freeze/samples/relimport/pkg1/__init__.py
new file mode 100644
index 0000000000..5a170fd2dd
--- /dev/null
+++ b/installer/cx_Freeze/samples/relimport/pkg1/__init__.py
@@ -0,0 +1,3 @@
+print "importing pkg1"
+from . import sub1
+from . import pkg2
diff --git a/installer/cx_Freeze/samples/relimport/pkg1/pkg2/__init__.py b/installer/cx_Freeze/samples/relimport/pkg1/pkg2/__init__.py
new file mode 100644
index 0000000000..71e0b1fbe6
--- /dev/null
+++ b/installer/cx_Freeze/samples/relimport/pkg1/pkg2/__init__.py
@@ -0,0 +1,3 @@
+print "importing pkg1.pkg2"
+from . import sub3
+from .. import sub4
diff --git a/installer/cx_Freeze/samples/relimport/pkg1/pkg2/sub3.py b/installer/cx_Freeze/samples/relimport/pkg1/pkg2/sub3.py
new file mode 100644
index 0000000000..1719aadb41
--- /dev/null
+++ b/installer/cx_Freeze/samples/relimport/pkg1/pkg2/sub3.py
@@ -0,0 +1,3 @@
+print "importing pkg1.pkg2.sub3"
+from . import sub5
+from .. import sub6
diff --git a/installer/cx_Freeze/samples/relimport/pkg1/pkg2/sub5.py b/installer/cx_Freeze/samples/relimport/pkg1/pkg2/sub5.py
new file mode 100644
index 0000000000..1c91b8fa23
--- /dev/null
+++ b/installer/cx_Freeze/samples/relimport/pkg1/pkg2/sub5.py
@@ -0,0 +1 @@
+print "importing pkg1.pkg2.sub5"
diff --git a/installer/cx_Freeze/samples/relimport/pkg1/sub1.py b/installer/cx_Freeze/samples/relimport/pkg1/sub1.py
new file mode 100644
index 0000000000..514bd88a87
--- /dev/null
+++ b/installer/cx_Freeze/samples/relimport/pkg1/sub1.py
@@ -0,0 +1,2 @@
+print "importing pkg1.sub1"
+from . import sub2
diff --git a/installer/cx_Freeze/samples/relimport/pkg1/sub2.py b/installer/cx_Freeze/samples/relimport/pkg1/sub2.py
new file mode 100644
index 0000000000..63a0838b25
--- /dev/null
+++ b/installer/cx_Freeze/samples/relimport/pkg1/sub2.py
@@ -0,0 +1 @@
+print "importing pkg1.sub2"
diff --git a/installer/cx_Freeze/samples/relimport/pkg1/sub4.py b/installer/cx_Freeze/samples/relimport/pkg1/sub4.py
new file mode 100644
index 0000000000..3a8e760e43
--- /dev/null
+++ b/installer/cx_Freeze/samples/relimport/pkg1/sub4.py
@@ -0,0 +1 @@
+print 'importing pkg1.sub4'
diff --git a/installer/cx_Freeze/samples/relimport/pkg1/sub6.py b/installer/cx_Freeze/samples/relimport/pkg1/sub6.py
new file mode 100644
index 0000000000..1e7d7955d6
--- /dev/null
+++ b/installer/cx_Freeze/samples/relimport/pkg1/sub6.py
@@ -0,0 +1 @@
+print "importing pkg1.sub6"
diff --git a/installer/cx_Freeze/samples/relimport/relimport.py b/installer/cx_Freeze/samples/relimport/relimport.py
new file mode 100644
index 0000000000..39cb50c91d
--- /dev/null
+++ b/installer/cx_Freeze/samples/relimport/relimport.py
@@ -0,0 +1 @@
+import pkg1
diff --git a/installer/cx_Freeze/samples/relimport/setup.py b/installer/cx_Freeze/samples/relimport/setup.py
new file mode 100644
index 0000000000..b8b3f3853b
--- /dev/null
+++ b/installer/cx_Freeze/samples/relimport/setup.py
@@ -0,0 +1,16 @@
+# relimport.py is a very simple script that tests importing using relative
+# imports (available in Python 2.5 and up)
+#
+# Run the build process by running the command 'python setup.py build'
+#
+# If everything works well you should find a subdirectory in the build
+# subdirectory that contains the files needed to run the script without Python
+
+from cx_Freeze import setup, Executable
+
+setup(
+ name = "relimport",
+ version = "0.1",
+ description = "Sample cx_Freeze script for relative imports",
+ executables = [Executable("relimport.py")])
+
diff --git a/installer/cx_Freeze/samples/simple/hello.py b/installer/cx_Freeze/samples/simple/hello.py
new file mode 100644
index 0000000000..0fb32405bc
--- /dev/null
+++ b/installer/cx_Freeze/samples/simple/hello.py
@@ -0,0 +1,19 @@
+import sys
+
+print "Hello from cx_Freeze"
+print
+
+print "sys.executable", sys.executable
+print "sys.prefix", sys.prefix
+print
+
+print "ARGUMENTS:"
+for a in sys.argv:
+ print a
+print
+
+print "PATH:"
+for p in sys.path:
+ print p
+print
+
diff --git a/installer/cx_Freeze/samples/simple/setup.py b/installer/cx_Freeze/samples/simple/setup.py
new file mode 100644
index 0000000000..25de838b10
--- /dev/null
+++ b/installer/cx_Freeze/samples/simple/setup.py
@@ -0,0 +1,18 @@
+# A very simple setup script to create a single executable
+#
+# hello.py is a very simple "Hello, world" type script which also displays the
+# environment in which the script runs
+#
+# Run the build process by running the command 'python setup.py build'
+#
+# If everything works well you should find a subdirectory in the build
+# subdirectory that contains the files needed to run the script without Python
+
+from cx_Freeze import setup, Executable
+
+setup(
+ name = "hello",
+ version = "0.1",
+ description = "Sample cx_Freeze script",
+ executables = [Executable("hello.py")])
+
diff --git a/installer/cx_Freeze/samples/wx/setup.py b/installer/cx_Freeze/samples/wx/setup.py
new file mode 100644
index 0000000000..9412996859
--- /dev/null
+++ b/installer/cx_Freeze/samples/wx/setup.py
@@ -0,0 +1,25 @@
+# A simple setup script to create an executable running wxPython. This also
+# demonstrates the method for creating a Windows executable that does not have
+# an associated console.
+#
+# wxapp.py is a very simple "Hello, world" type wxPython application
+#
+# Run the build process by running the command 'python setup.py build'
+#
+# If everything works well you should find a subdirectory in the build
+# subdirectory that contains the files needed to run the application
+
+import sys
+
+from cx_Freeze import setup, Executable
+
+base = None
+if sys.platform == "win32":
+ base = "Win32GUI"
+
+setup(
+ name = "hello",
+ version = "0.1",
+ description = "Sample cx_Freeze wxPython script",
+ executables = [Executable("wxapp.py", base = base)])
+
diff --git a/installer/cx_Freeze/samples/wx/wxapp.py b/installer/cx_Freeze/samples/wx/wxapp.py
new file mode 100644
index 0000000000..7baa90b8d1
--- /dev/null
+++ b/installer/cx_Freeze/samples/wx/wxapp.py
@@ -0,0 +1,42 @@
+import wx
+
+class Frame(wx.Frame):
+
+ def __init__(self):
+ wx.Frame.__init__(self, parent = None, title = "Hello from cx_Freeze")
+ panel = wx.Panel(self)
+ closeMeButton = wx.Button(panel, -1, "Close Me")
+ wx.EVT_BUTTON(self, closeMeButton.GetId(), self.OnCloseMe)
+ wx.EVT_CLOSE(self, self.OnCloseWindow)
+ pushMeButton = wx.Button(panel, -1, "Push Me")
+ wx.EVT_BUTTON(self, pushMeButton.GetId(), self.OnPushMe)
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+ sizer.Add(closeMeButton, flag = wx.ALL, border = 20)
+ sizer.Add(pushMeButton, flag = wx.ALL, border = 20)
+ panel.SetSizer(sizer)
+ topSizer = wx.BoxSizer(wx.VERTICAL)
+ topSizer.Add(panel, flag = wx.ALL | wx.EXPAND)
+ topSizer.Fit(self)
+
+ def OnCloseMe(self, event):
+ self.Close(True)
+
+ def OnPushMe(self, event):
+ 1 / 0
+
+ def OnCloseWindow(self, event):
+ self.Destroy()
+
+
+class App(wx.App):
+
+ def OnInit(self):
+ frame = Frame()
+ frame.Show(True)
+ self.SetTopWindow(frame)
+ return True
+
+
+app = App(1)
+app.MainLoop()
+
diff --git a/installer/cx_Freeze/setup.py b/installer/cx_Freeze/setup.py
new file mode 100755
index 0000000000..b51453aa7a
--- /dev/null
+++ b/installer/cx_Freeze/setup.py
@@ -0,0 +1,197 @@
+"""
+Distutils script for cx_Freeze.
+"""
+
+import distutils.command.bdist_rpm
+import distutils.command.build_ext
+import distutils.command.build_scripts
+import distutils.command.install
+import distutils.command.install_data
+import distutils.sysconfig
+import os
+import sys
+
+from distutils.core import setup
+from distutils.extension import Extension
+
+class bdist_rpm(distutils.command.bdist_rpm.bdist_rpm):
+
+ # rpm automatically byte compiles all Python files in a package but we
+ # don't want that to happen for initscripts and samples so we tell it to
+ # ignore those files
+ def _make_spec_file(self):
+ specFile = distutils.command.bdist_rpm.bdist_rpm._make_spec_file(self)
+ specFile.insert(0, "%define _unpackaged_files_terminate_build 0%{nil}")
+ return specFile
+
+ def run(self):
+ distutils.command.bdist_rpm.bdist_rpm.run(self)
+ specFile = os.path.join(self.rpm_base, "SPECS",
+ "%s.spec" % self.distribution.get_name())
+ queryFormat = "%{name}-%{version}-%{release}.%{arch}.rpm"
+ command = "rpm -q --qf '%s' --specfile %s" % (queryFormat, specFile)
+ origFileName = os.popen(command).read()
+ parts = origFileName.split("-")
+ parts.insert(2, "py%s%s" % sys.version_info[:2])
+ newFileName = "-".join(parts)
+ self.move_file(os.path.join("dist", origFileName),
+ os.path.join("dist", newFileName))
+
+
+class build_ext(distutils.command.build_ext.build_ext):
+
+ def build_extension(self, ext):
+ if ext.name.find("bases") < 0:
+ distutils.command.build_ext.build_ext.build_extension(self, ext)
+ return
+ os.environ["LD_RUN_PATH"] = "${ORIGIN}:${ORIGIN}/../lib"
+ objects = self.compiler.compile(ext.sources,
+ output_dir = self.build_temp,
+ include_dirs = ext.include_dirs,
+ debug = self.debug,
+ depends = ext.depends)
+ fileName = os.path.splitext(self.get_ext_filename(ext.name))[0]
+ fullName = os.path.join(self.build_lib, fileName)
+ libraryDirs = ext.library_dirs or []
+ libraries = self.get_libraries(ext)
+ extraArgs = ext.extra_link_args or []
+ if sys.platform != "win32":
+ vars = distutils.sysconfig.get_config_vars()
+ libraryDirs.append(vars["LIBPL"])
+ libraries.append("python%s.%s" % sys.version_info[:2])
+ if vars["LINKFORSHARED"]:
+ extraArgs.extend(vars["LINKFORSHARED"].split())
+ if vars["LIBS"]:
+ extraArgs.extend(vars["LIBS"].split())
+ if vars["LIBM"]:
+ extraArgs.append(vars["LIBM"])
+ if vars["BASEMODLIBS"]:
+ extraArgs.extend(vars["BASEMODLIBS"].split())
+ if vars["LOCALMODLIBS"]:
+ extraArgs.extend(vars["LOCALMODLIBS"].split())
+ extraArgs.append("-s")
+ self.compiler.link_executable(objects, fullName,
+ libraries = libraries,
+ library_dirs = libraryDirs,
+ runtime_library_dirs = ext.runtime_library_dirs,
+ extra_postargs = extraArgs,
+ debug = self.debug)
+
+ def get_ext_filename(self, name):
+ fileName = distutils.command.build_ext.build_ext.get_ext_filename(self,
+ name)
+ if name.find("bases") < 0:
+ return fileName
+ ext = self.compiler.exe_extension or ""
+ return os.path.splitext(fileName)[0] + ext
+
+
+class build_scripts(distutils.command.build_scripts.build_scripts):
+
+ def copy_scripts(self):
+ distutils.command.build_scripts.build_scripts.copy_scripts(self)
+ if sys.platform == "win32":
+ for script in self.scripts:
+ batFileName = os.path.join(self.build_dir, script + ".bat")
+ fullScriptName = r"%s\Scripts\%s" % \
+ (os.path.dirname(sys.executable), script)
+ command = "%s %s %%1 %%2 %%3 %%4 %%5 %%6 %%7 %%8 %%9" % \
+ (sys.executable, fullScriptName)
+ file(batFileName, "w").write("@echo off\n\n%s" % command)
+
+
+class install(distutils.command.install.install):
+
+ def get_sub_commands(self):
+ subCommands = distutils.command.install.install.get_sub_commands(self)
+ subCommands.append("install_packagedata")
+ return subCommands
+
+
+class install_packagedata(distutils.command.install_data.install_data):
+
+ def run(self):
+ installCommand = self.get_finalized_command("install")
+ installDir = getattr(installCommand, "install_lib")
+ sourceDirs = ["samples", "initscripts"]
+ while sourceDirs:
+ sourceDir = sourceDirs.pop(0)
+ targetDir = os.path.join(installDir, "cx_Freeze", sourceDir)
+ self.mkpath(targetDir)
+ for name in os.listdir(sourceDir):
+ if name == "build" or name.startswith("."):
+ continue
+ fullSourceName = os.path.join(sourceDir, name)
+ if os.path.isdir(fullSourceName):
+ sourceDirs.append(fullSourceName)
+ else:
+ fullTargetName = os.path.join(targetDir, name)
+ self.copy_file(fullSourceName, fullTargetName)
+ self.outfiles.append(fullTargetName)
+
+
+commandClasses = dict(
+ build_ext = build_ext,
+ build_scripts = build_scripts,
+ bdist_rpm = bdist_rpm,
+ install = install,
+ install_packagedata = install_packagedata)
+
+if sys.platform == "win32":
+ libraries = ["imagehlp"]
+else:
+ libraries = []
+utilModule = Extension("cx_Freeze.util", ["source/util.c"],
+ libraries = libraries)
+depends = ["source/bases/Common.c"]
+if sys.platform == "win32":
+ if sys.version_info[:2] >= (2, 6):
+ extraSources = ["source/bases/manifest.rc"]
+ else:
+ extraSources = ["source/bases/dummy.rc"]
+else:
+ extraSources = []
+console = Extension("cx_Freeze.bases.Console",
+ ["source/bases/Console.c"] + extraSources, depends = depends)
+consoleKeepPath = Extension("cx_Freeze.bases.ConsoleKeepPath",
+ ["source/bases/ConsoleKeepPath.c"] + extraSources, depends = depends)
+extensions = [utilModule, console, consoleKeepPath]
+if sys.platform == "win32":
+ gui = Extension("cx_Freeze.bases.Win32GUI",
+ ["source/bases/Win32GUI.c"] + extraSources,
+ depends = depends, extra_link_args = ["-mwindows"])
+ extensions.append(gui)
+
+docFiles = "LICENSE.txt README.txt HISTORY.txt doc/cx_Freeze.html"
+
+classifiers = [
+ "Development Status :: 5 - Production/Stable",
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: Python Software Foundation License",
+ "Natural Language :: English",
+ "Operating System :: OS Independent",
+ "Programming Language :: C",
+ "Programming Language :: Python",
+ "Topic :: Software Development :: Build Tools",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ "Topic :: System :: Software Distribution",
+ "Topic :: Utilities"
+]
+
+setup(name = "cx_Freeze",
+ description = "create standalone executables from Python scripts",
+ long_description = "create standalone executables from Python scripts",
+ version = "4.0.1",
+ cmdclass = commandClasses,
+ options = dict(bdist_rpm = dict(doc_files = docFiles),
+ install = dict(optimize = 1)),
+ ext_modules = extensions,
+ packages = ['cx_Freeze'],
+ maintainer="Anthony Tuininga",
+ maintainer_email="anthony.tuininga@gmail.com",
+ url = "http://cx-freeze.sourceforge.net",
+ scripts = ["cxfreeze"],
+ classifiers = classifiers,
+ keywords = "freeze",
+ license = "Python Software Foundation License")
+
diff --git a/installer/cx_Freeze/source/bases/Common.c b/installer/cx_Freeze/source/bases/Common.c
new file mode 100644
index 0000000000..ce1e137ebb
--- /dev/null
+++ b/installer/cx_Freeze/source/bases/Common.c
@@ -0,0 +1,262 @@
+//-----------------------------------------------------------------------------
+// Common.c
+// Routines which are common to running frozen executables.
+//-----------------------------------------------------------------------------
+
+#include
+#include
+#include
+
+// global variables (used for simplicity)
+static PyObject *g_FileName = NULL;
+static PyObject *g_DirName = NULL;
+static PyObject *g_ExclusiveZipFileName = NULL;
+static PyObject *g_SharedZipFileName = NULL;
+static PyObject *g_InitScriptZipFileName = NULL;
+
+//-----------------------------------------------------------------------------
+// GetDirName()
+// Return the directory name of the given path.
+//-----------------------------------------------------------------------------
+static int GetDirName(
+ const char *path, // path to calculate dir name for
+ PyObject **dirName) // directory name (OUT)
+{
+ int i;
+
+ for (i = strlen(path); i > 0 && path[i] != SEP; --i);
+ *dirName = PyString_FromStringAndSize(path, i);
+ if (!*dirName)
+ return FatalError("cannot create string for directory name");
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// SetExecutableName()
+// Set the script to execute and calculate the directory in which the
+// executable is found as well as the exclusive (only for this executable) and
+// shared zip file names.
+//-----------------------------------------------------------------------------
+static int SetExecutableName(
+ const char *fileName) // script to execute
+{
+ char temp[MAXPATHLEN + 12], *ptr;
+#ifndef WIN32
+ char linkData[MAXPATHLEN + 1];
+ struct stat statData;
+ size_t linkSize, i;
+ PyObject *dirName;
+#endif
+
+ // store file name
+ g_FileName = PyString_FromString(fileName);
+ if (!g_FileName)
+ return FatalError("cannot create string for file name");
+
+#ifndef WIN32
+ for (i = 0; i < 25; i++) {
+ if (lstat(fileName, &statData) < 0) {
+ PyErr_SetFromErrnoWithFilename(PyExc_OSError, (char*) fileName);
+ return FatalError("unable to stat file");
+ }
+ if (!S_ISLNK(statData.st_mode))
+ break;
+ linkSize = readlink(fileName, linkData, sizeof(linkData));
+ if (linkSize < 0) {
+ PyErr_SetFromErrnoWithFilename(PyExc_OSError, (char*) fileName);
+ return FatalError("unable to stat file");
+ }
+ if (linkData[0] == '/') {
+ Py_DECREF(g_FileName);
+ g_FileName = PyString_FromStringAndSize(linkData, linkSize);
+ } else {
+ if (GetDirName(PyString_AS_STRING(g_FileName), &dirName) < 0)
+ return -1;
+ if (PyString_GET_SIZE(dirName) + linkSize + 1 > MAXPATHLEN) {
+ Py_DECREF(dirName);
+ return FatalError("cannot dereference link, path too large");
+ }
+ strcpy(temp, PyString_AS_STRING(dirName));
+ strcat(temp, "/");
+ strcat(temp, linkData);
+ Py_DECREF(g_FileName);
+ g_FileName = PyString_FromString(temp);
+ }
+ if (!g_FileName)
+ return FatalError("cannot create string for linked file name");
+ fileName = PyString_AS_STRING(g_FileName);
+ }
+#endif
+
+ // calculate and store directory name
+ if (GetDirName(fileName, &g_DirName) < 0)
+ return -1;
+
+ // calculate and store exclusive zip file name
+ strcpy(temp, fileName);
+ ptr = temp + strlen(temp) - 1;
+ while (ptr > temp && *ptr != SEP && *ptr != '.')
+ ptr--;
+ if (*ptr == '.')
+ *ptr = '\0';
+ strcat(temp, ".zip");
+ g_ExclusiveZipFileName = PyString_FromString(temp);
+ if (!g_ExclusiveZipFileName)
+ return FatalError("cannot create string for exclusive zip file name");
+
+ // calculate and store shared zip file name
+ strcpy(temp, PyString_AS_STRING(g_DirName));
+ ptr = temp + strlen(temp);
+ *ptr++ = SEP;
+ strcpy(ptr, "library.zip");
+ g_SharedZipFileName = PyString_FromString(temp);
+ if (!g_SharedZipFileName)
+ return FatalError("cannot create string for shared zip file name");
+
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// SetPathToSearch()
+// Set the path to search. This includes the file (for those situations where
+// a zip file is attached to the executable itself), the directory where the
+// executable is found (to search for extensions), the exclusive zip file
+// name and the shared zip file name.
+//-----------------------------------------------------------------------------
+static int SetPathToSearch(void)
+{
+ PyObject *pathList;
+
+ pathList = PySys_GetObject("path");
+ if (!pathList)
+ return FatalError("cannot acquire sys.path");
+ if (PyList_Insert(pathList, 0, g_FileName) < 0)
+ return FatalError("cannot insert file name into sys.path");
+ if (PyList_Insert(pathList, 1, g_DirName) < 0)
+ return FatalError("cannot insert directory name into sys.path");
+ if (PyList_Insert(pathList, 2, g_ExclusiveZipFileName) < 0)
+ return FatalError("cannot insert exclusive zip name into sys.path");
+ if (PyList_Insert(pathList, 3, g_SharedZipFileName) < 0)
+ return FatalError("cannot insert shared zip name into sys.path");
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// GetImporterHelper()
+// Helper which is used to locate the importer for the initscript.
+//-----------------------------------------------------------------------------
+static PyObject *GetImporterHelper(
+ PyObject *module, // zipimport module
+ PyObject *fileName) // name of file to search
+{
+ PyObject *importer;
+
+ importer = PyObject_CallMethod(module, "zipimporter", "O", fileName);
+ if (importer)
+ g_InitScriptZipFileName = fileName;
+ else
+ PyErr_Clear();
+ return importer;
+}
+
+
+//-----------------------------------------------------------------------------
+// GetImporter()
+// Return the importer which will be used for importing the initialization
+// script. The executable itself is searched first, followed by the exclusive
+// zip file and finally by the shared zip file.
+//-----------------------------------------------------------------------------
+static int GetImporter(
+ PyObject **importer) // importer (OUT)
+{
+ PyObject *module;
+
+ module = PyImport_ImportModule("zipimport");
+ if (!module)
+ return FatalError("cannot import zipimport module");
+ *importer = GetImporterHelper(module, g_FileName);
+ if (!*importer) {
+ *importer = GetImporterHelper(module, g_ExclusiveZipFileName);
+ if (!*importer)
+ *importer = GetImporterHelper(module, g_SharedZipFileName);
+ }
+ Py_DECREF(module);
+ if (!*importer)
+ return FatalError("cannot get zipimporter instance");
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// PopulateInitScriptDict()
+// Return the dictionary used by the initialization script.
+//-----------------------------------------------------------------------------
+static int PopulateInitScriptDict(
+ PyObject *dict) // dictionary to populate
+{
+ if (!dict)
+ return FatalError("unable to create temporary dictionary");
+ if (PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins()) < 0)
+ return FatalError("unable to set __builtins__");
+ if (PyDict_SetItemString(dict, "FILE_NAME", g_FileName) < 0)
+ return FatalError("unable to set FILE_NAME");
+ if (PyDict_SetItemString(dict, "DIR_NAME", g_DirName) < 0)
+ return FatalError("unable to set DIR_NAME");
+ if (PyDict_SetItemString(dict, "EXCLUSIVE_ZIP_FILE_NAME",
+ g_ExclusiveZipFileName) < 0)
+ return FatalError("unable to set EXCLUSIVE_ZIP_FILE_NAME");
+ if (PyDict_SetItemString(dict, "SHARED_ZIP_FILE_NAME",
+ g_SharedZipFileName) < 0)
+ return FatalError("unable to set SHARED_ZIP_FILE_NAME");
+ if (PyDict_SetItemString(dict, "INITSCRIPT_ZIP_FILE_NAME",
+ g_InitScriptZipFileName) < 0)
+ return FatalError("unable to set INITSCRIPT_ZIP_FILE_NAME");
+ return 0;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// ExecuteScript()
+// Execute the script found within the file.
+//-----------------------------------------------------------------------------
+static int ExecuteScript(
+ const char *fileName) // name of file containing Python code
+{
+ PyObject *importer, *dict, *code, *temp;
+
+ if (SetExecutableName(fileName) < 0)
+ return -1;
+ if (SetPathToSearch() < 0)
+ return -1;
+ importer = NULL;
+ if (GetImporter(&importer) < 0)
+ return -1;
+
+ // create and populate dictionary for initscript module
+ dict = PyDict_New();
+ if (PopulateInitScriptDict(dict) < 0) {
+ Py_XDECREF(dict);
+ Py_DECREF(importer);
+ return -1;
+ }
+
+ // locate and execute script
+ code = PyObject_CallMethod(importer, "get_code", "s", "cx_Freeze__init__");
+ Py_DECREF(importer);
+ if (!code)
+ return FatalError("unable to locate initialization module");
+ temp = PyEval_EvalCode( (PyCodeObject*) code, dict, dict);
+ Py_DECREF(code);
+ Py_DECREF(dict);
+ if (!temp)
+ return FatalScriptError();
+ Py_DECREF(temp);
+
+ return 0;
+}
+
diff --git a/installer/cx_Freeze/source/bases/Console.c b/installer/cx_Freeze/source/bases/Console.c
new file mode 100644
index 0000000000..d6a8a515a0
--- /dev/null
+++ b/installer/cx_Freeze/source/bases/Console.c
@@ -0,0 +1,72 @@
+//-----------------------------------------------------------------------------
+// Console.c
+// Main routine for frozen programs which run in a console.
+//-----------------------------------------------------------------------------
+
+#include
+#ifdef __WIN32__
+#include
+#endif
+
+//-----------------------------------------------------------------------------
+// FatalError()
+// Prints a fatal error.
+//-----------------------------------------------------------------------------
+static int FatalError(
+ const char *message) // message to print
+{
+ PyErr_Print();
+ Py_FatalError(message);
+ return -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// FatalScriptError()
+// Prints a fatal error in the initialization script.
+//-----------------------------------------------------------------------------
+static int FatalScriptError(void)
+{
+ PyErr_Print();
+ return -1;
+}
+
+
+#include "Common.c"
+
+
+//-----------------------------------------------------------------------------
+// main()
+// Main routine for frozen programs.
+//-----------------------------------------------------------------------------
+int main(int argc, char **argv)
+{
+ const char *fileName;
+ char *encoding;
+
+ // initialize Python
+ Py_NoSiteFlag = 1;
+ Py_FrozenFlag = 1;
+ Py_IgnoreEnvironmentFlag = 1;
+
+ encoding = getenv("PYTHONIOENCODING");
+ if (encoding != NULL) {
+ Py_FileSystemDefaultEncoding = strndup(encoding, 100);
+ }
+
+ Py_SetPythonHome("");
+ Py_SetProgramName(argv[0]);
+ fileName = Py_GetProgramFullPath();
+
+ Py_Initialize();
+ PySys_SetArgv(argc, argv);
+
+
+ // do the work
+ if (ExecuteScript(fileName) < 0)
+ return 1;
+
+ Py_Finalize();
+ return 0;
+}
+
diff --git a/installer/cx_Freeze/source/bases/ConsoleKeepPath.c b/installer/cx_Freeze/source/bases/ConsoleKeepPath.c
new file mode 100644
index 0000000000..3ad00f8488
--- /dev/null
+++ b/installer/cx_Freeze/source/bases/ConsoleKeepPath.c
@@ -0,0 +1,60 @@
+//-----------------------------------------------------------------------------
+// ConsoleKeepPath.c
+// Main routine for frozen programs which need a Python installation to do
+// their work.
+//-----------------------------------------------------------------------------
+
+#include
+#ifdef __WIN32__
+#include
+#endif
+
+//-----------------------------------------------------------------------------
+// FatalError()
+// Prints a fatal error.
+//-----------------------------------------------------------------------------
+static int FatalError(
+ const char *message) // message to print
+{
+ PyErr_Print();
+ Py_FatalError(message);
+ return -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// FatalScriptError()
+// Prints a fatal error in the initialization script.
+//-----------------------------------------------------------------------------
+static int FatalScriptError(void)
+{
+ PyErr_Print();
+ return -1;
+}
+
+
+#include "Common.c"
+
+
+//-----------------------------------------------------------------------------
+// main()
+// Main routine for frozen programs.
+//-----------------------------------------------------------------------------
+int main(int argc, char **argv)
+{
+ const char *fileName;
+
+ // initialize Python
+ Py_SetProgramName(argv[0]);
+ fileName = Py_GetProgramFullPath();
+ Py_Initialize();
+ PySys_SetArgv(argc, argv);
+
+ // do the work
+ if (ExecuteScript(fileName) < 0)
+ return 1;
+
+ Py_Finalize();
+ return 0;
+}
+
diff --git a/installer/cx_Freeze/source/bases/Win32GUI.c b/installer/cx_Freeze/source/bases/Win32GUI.c
new file mode 100644
index 0000000000..f5bbe74dba
--- /dev/null
+++ b/installer/cx_Freeze/source/bases/Win32GUI.c
@@ -0,0 +1,242 @@
+//-----------------------------------------------------------------------------
+// Win32GUI.c
+// Main routine for frozen programs written for the Win32 GUI subsystem.
+//-----------------------------------------------------------------------------
+
+#include
+#include
+
+//-----------------------------------------------------------------------------
+// FatalError()
+// Handle a fatal error.
+//-----------------------------------------------------------------------------
+static int FatalError(
+ char *a_Message) // message to display
+{
+ MessageBox(NULL, a_Message, "cx_Freeze Fatal Error", MB_ICONERROR);
+ Py_Finalize();
+ return -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// StringifyObject()
+// Stringify a Python object.
+//-----------------------------------------------------------------------------
+static char *StringifyObject(
+ PyObject *object, // object to stringify
+ PyObject **stringRep) // string representation
+{
+ if (object) {
+ *stringRep = PyObject_Str(object);
+ if (*stringRep)
+ return PyString_AS_STRING(*stringRep);
+ return "Unable to stringify";
+ }
+
+ // object is NULL
+ *stringRep = NULL;
+ return "None";
+}
+
+
+//-----------------------------------------------------------------------------
+// FatalPythonErrorNoTraceback()
+// Handle a fatal Python error without traceback.
+//-----------------------------------------------------------------------------
+static int FatalPythonErrorNoTraceback(
+ PyObject *origType, // exception type
+ PyObject *origValue, // exception value
+ char *message) // message to display
+{
+ PyObject *typeStrRep, *valueStrRep, *origTypeStrRep, *origValueStrRep;
+ char *totalMessage, *typeStr, *valueStr, *origTypeStr, *origValueStr;
+ PyObject *type, *value, *traceback;
+ int totalMessageLength;
+ char *messageFormat;
+
+ // fetch error and string representations of the error
+ PyErr_Fetch(&type, &value, &traceback);
+ origTypeStr = StringifyObject(origType, &origTypeStrRep);
+ origValueStr = StringifyObject(origValue, &origValueStrRep);
+ typeStr = StringifyObject(type, &typeStrRep);
+ valueStr = StringifyObject(value, &valueStrRep);
+
+ // fill out the message to be displayed
+ messageFormat = "Type: %s\nValue: %s\nOther Type: %s\nOtherValue: %s\n%s";
+ totalMessageLength = strlen(origTypeStr) + strlen(origValueStr) +
+ strlen(typeStr) + strlen(valueStr) + strlen(message) +
+ strlen(messageFormat) + 1;
+ totalMessage = malloc(totalMessageLength);
+ if (!totalMessage)
+ return FatalError("Out of memory!");
+ sprintf(totalMessage, messageFormat, typeStr, valueStr, origTypeStr,
+ origValueStr, message);
+
+ // display the message
+ MessageBox(NULL, totalMessage,
+ "cx_Freeze: Python error in main script (traceback unavailable)",
+ MB_ICONERROR);
+ free(totalMessage);
+ return -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// ArgumentValue()
+// Return a suitable argument value by replacing NULL with Py_None.
+//-----------------------------------------------------------------------------
+static PyObject *ArgumentValue(
+ PyObject *object) // argument to massage
+{
+ if (object) {
+ Py_INCREF(object);
+ return object;
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+//-----------------------------------------------------------------------------
+// HandleSystemExitException()
+// Handles a system exit exception differently. If an integer value is passed
+// through then that becomes the exit value; otherwise the string value of the
+// value passed through is displayed in a message box.
+//-----------------------------------------------------------------------------
+static void HandleSystemExitException()
+{
+ PyObject *type, *value, *traceback, *valueStr;
+ int exitCode = 0;
+ char *message;
+
+ PyErr_Fetch(&type, &value, &traceback);
+ if (PyInstance_Check(value)) {
+ PyObject *code = PyObject_GetAttrString(value, "code");
+ if (code) {
+ Py_DECREF(value);
+ value = code;
+ if (value == Py_None)
+ Py_Exit(0);
+ }
+ }
+ if (PyInt_Check(value))
+ exitCode = PyInt_AsLong(value);
+ else {
+ message = StringifyObject(value, &valueStr);
+ MessageBox(NULL, message, "cx_Freeze: Application Terminated",
+ MB_ICONERROR);
+ Py_XDECREF(valueStr);
+ exitCode = 1;
+ }
+ Py_Exit(exitCode);
+}
+
+
+//-----------------------------------------------------------------------------
+// FatalScriptError()
+// Handle a fatal Python error with traceback.
+//-----------------------------------------------------------------------------
+static int FatalScriptError()
+{
+ PyObject *type, *value, *traceback, *argsTuple, *module, *method, *result;
+ int tracebackLength, i;
+ char *tracebackStr;
+
+ // if a system exception, handle it specially
+ if (PyErr_ExceptionMatches(PyExc_SystemExit))
+ HandleSystemExitException();
+
+ // get the exception details
+ PyErr_Fetch(&type, &value, &traceback);
+
+ // import the traceback module
+ module = PyImport_ImportModule("traceback");
+ if (!module)
+ return FatalPythonErrorNoTraceback(type, value,
+ "Cannot import traceback module.");
+
+ // get the format_exception method
+ method = PyObject_GetAttrString(module, "format_exception");
+ Py_DECREF(module);
+ if (!method)
+ return FatalPythonErrorNoTraceback(type, value,
+ "Cannot get format_exception method.");
+
+ // create a tuple for the arguments
+ argsTuple = PyTuple_New(3);
+ if (!argsTuple) {
+ Py_DECREF(method);
+ return FatalPythonErrorNoTraceback(type, value,
+ "Cannot create arguments tuple for traceback.");
+ }
+ PyTuple_SET_ITEM(argsTuple, 0, ArgumentValue(type));
+ PyTuple_SET_ITEM(argsTuple, 1, ArgumentValue(value));
+ PyTuple_SET_ITEM(argsTuple, 2, ArgumentValue(traceback));
+
+ // call the format_exception method
+ result = PyObject_CallObject(method, argsTuple);
+ Py_DECREF(method);
+ Py_DECREF(argsTuple);
+ if (!result)
+ return FatalPythonErrorNoTraceback(type, value,
+ "Failed calling format_exception method.");
+
+ // determine length of string representation of formatted traceback
+ tracebackLength = 1;
+ for (i = 0; i < PyList_GET_SIZE(result); i++)
+ tracebackLength += PyString_GET_SIZE(PyList_GET_ITEM(result, i));
+
+ // create a string representation of the formatted traceback
+ tracebackStr = malloc(tracebackLength);
+ if (!tracebackStr) {
+ Py_DECREF(result);
+ return FatalError("Out of memory!");
+ }
+ tracebackStr[0] = '\0';
+ for (i = 0; i < PyList_GET_SIZE(result); i++)
+ strcat(tracebackStr, PyString_AS_STRING(PyList_GET_ITEM(result, i)));
+ Py_DECREF(result);
+
+ // bring up the error
+ MessageBox(NULL, tracebackStr, "cx_Freeze: Python error in main script",
+ MB_ICONERROR);
+ Py_Finalize();
+ return 1;
+}
+
+
+#include "Common.c"
+
+
+//-----------------------------------------------------------------------------
+// WinMain()
+// Main routine for the executable in Windows.
+//-----------------------------------------------------------------------------
+int WINAPI WinMain(
+ HINSTANCE instance, // handle to application
+ HINSTANCE prevInstance, // previous handle to application
+ LPSTR commandLine, // command line
+ int showFlag) // show flag
+{
+ const char *fileName;
+
+ // initialize Python
+ Py_NoSiteFlag = 1;
+ Py_FrozenFlag = 1;
+ Py_IgnoreEnvironmentFlag = 1;
+ Py_SetPythonHome("");
+ Py_SetProgramName(__argv[0]);
+ fileName = Py_GetProgramFullPath();
+ Py_Initialize();
+ PySys_SetArgv(__argc, __argv);
+
+ // do the work
+ if (ExecuteScript(fileName) < 0)
+ return 1;
+
+ // terminate Python
+ Py_Finalize();
+ return 0;
+}
+
diff --git a/installer/cx_Freeze/source/bases/dummy.rc b/installer/cx_Freeze/source/bases/dummy.rc
new file mode 100644
index 0000000000..5c1fa1a194
--- /dev/null
+++ b/installer/cx_Freeze/source/bases/dummy.rc
@@ -0,0 +1,5 @@
+STRINGTABLE
+{
+ 1, "Just to ensure that buggy EndUpdateResource doesn't fall over."
+}
+
diff --git a/installer/cx_Freeze/source/bases/manifest.rc b/installer/cx_Freeze/source/bases/manifest.rc
new file mode 100644
index 0000000000..2b7ee27ab5
--- /dev/null
+++ b/installer/cx_Freeze/source/bases/manifest.rc
@@ -0,0 +1,3 @@
+#include "dummy.rc"
+
+1 24 source/bases/manifest.txt
diff --git a/installer/cx_Freeze/source/util.c b/installer/cx_Freeze/source/util.c
new file mode 100644
index 0000000000..1c8eb0c0ca
--- /dev/null
+++ b/installer/cx_Freeze/source/util.c
@@ -0,0 +1,418 @@
+//-----------------------------------------------------------------------------
+// util.c
+// Shared library for use by cx_Freeze.
+//-----------------------------------------------------------------------------
+
+#include
+
+#ifdef WIN32
+#include
+#include
+
+#pragma pack(2)
+
+typedef struct {
+ BYTE bWidth; // Width, in pixels, of the image
+ BYTE bHeight; // Height, in pixels, of the image
+ BYTE bColorCount; // Number of colors in image
+ BYTE bReserved; // Reserved ( must be 0)
+ WORD wPlanes; // Color Planes
+ WORD wBitCount; // Bits per pixel
+ DWORD dwBytesInRes; // How many bytes in this resource?
+ DWORD dwImageOffset; // Where in the file is this image?
+} ICONDIRENTRY;
+
+typedef struct {
+ WORD idReserved; // Reserved (must be 0)
+ WORD idType; // Resource Type (1 for icons)
+ WORD idCount; // How many images?
+ ICONDIRENTRY idEntries[0]; // An entry for each image
+} ICONDIR;
+
+typedef struct {
+ BYTE bWidth; // Width, in pixels, of the image
+ BYTE bHeight; // Height, in pixels, of the image
+ BYTE bColorCount; // Number of colors in image
+ BYTE bReserved; // Reserved ( must be 0)
+ WORD wPlanes; // Color Planes
+ WORD wBitCount; // Bits per pixel
+ DWORD dwBytesInRes; // How many bytes in this resource?
+ WORD nID; // resource ID
+} GRPICONDIRENTRY;
+
+typedef struct {
+ WORD idReserved; // Reserved (must be 0)
+ WORD idType; // Resource Type (1 for icons)
+ WORD idCount; // How many images?
+ GRPICONDIRENTRY idEntries[0]; // An entry for each image
+} GRPICONDIR;
+#endif
+
+//-----------------------------------------------------------------------------
+// Globals
+//-----------------------------------------------------------------------------
+#ifdef WIN32
+static PyObject *g_BindErrorException = NULL;
+static PyObject *g_ImageNames = NULL;
+#endif
+
+
+#ifdef WIN32
+//-----------------------------------------------------------------------------
+// BindStatusRoutine()
+// Called by BindImageEx() at various points. This is used to determine the
+// dependency tree which is later examined by cx_Freeze.
+//-----------------------------------------------------------------------------
+static BOOL __stdcall BindStatusRoutine(
+ IMAGEHLP_STATUS_REASON reason, // reason called
+ PSTR imageName, // name of image being examined
+ PSTR dllName, // name of DLL
+ ULONG virtualAddress, // computed virtual address
+ ULONG parameter) // parameter (value depends on reason)
+{
+ char fileName[MAX_PATH + 1];
+
+ switch (reason) {
+ case BindImportModule:
+ if (!SearchPath(NULL, dllName, NULL, sizeof(fileName), fileName,
+ NULL))
+ return FALSE;
+ Py_INCREF(Py_None);
+ if (PyDict_SetItemString(g_ImageNames, fileName, Py_None) < 0)
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+
+//-----------------------------------------------------------------------------
+// GetFileData()
+// Return the data for the given file.
+//-----------------------------------------------------------------------------
+static int GetFileData(
+ const char *fileName, // name of file to read
+ char **data) // pointer to data (OUT)
+{
+ DWORD numberOfBytesRead, dataSize;
+ HANDLE file;
+
+ file = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (file == INVALID_HANDLE_VALUE)
+ return -1;
+ dataSize = GetFileSize(file, NULL);
+ if (dataSize == INVALID_FILE_SIZE) {
+ CloseHandle(file);
+ return -1;
+ }
+ *data = PyMem_Malloc(dataSize);
+ if (!*data) {
+ CloseHandle(file);
+ return -1;
+ }
+ if (!ReadFile(file, *data, dataSize, &numberOfBytesRead, NULL)) {
+ CloseHandle(file);
+ return -1;
+ }
+ CloseHandle(file);
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// CreateGroupIconResource()
+// Return the group icon resource given the icon file data.
+//-----------------------------------------------------------------------------
+static GRPICONDIR *CreateGroupIconResource(
+ ICONDIR *iconDir, // icon information
+ DWORD *resourceSize) // size of resource (OUT)
+{
+ GRPICONDIR *groupIconDir;
+ int i;
+
+ *resourceSize = sizeof(GRPICONDIR) +
+ sizeof(GRPICONDIRENTRY) * iconDir->idCount;
+ groupIconDir = PyMem_Malloc(*resourceSize);
+ if (!groupIconDir)
+ return NULL;
+ groupIconDir->idReserved = iconDir->idReserved;
+ groupIconDir->idType = iconDir->idType;
+ groupIconDir->idCount = iconDir->idCount;
+ for (i = 0; i < iconDir->idCount; i++) {
+ groupIconDir->idEntries[i].bWidth = iconDir->idEntries[i].bWidth;
+ groupIconDir->idEntries[i].bHeight = iconDir->idEntries[i].bHeight;
+ groupIconDir->idEntries[i].bColorCount =
+ iconDir->idEntries[i].bColorCount;
+ groupIconDir->idEntries[i].bReserved = iconDir->idEntries[i].bReserved;
+ groupIconDir->idEntries[i].wPlanes = iconDir->idEntries[i].wPlanes;
+ groupIconDir->idEntries[i].wBitCount = iconDir->idEntries[i].wBitCount;
+ groupIconDir->idEntries[i].dwBytesInRes =
+ iconDir->idEntries[i].dwBytesInRes;
+ groupIconDir->idEntries[i].nID = i + 1;
+ }
+
+ return groupIconDir;
+}
+
+
+//-----------------------------------------------------------------------------
+// ExtAddIcon()
+// Add the icon as a resource to the specified file.
+//-----------------------------------------------------------------------------
+static PyObject *ExtAddIcon(
+ PyObject *self, // passthrough argument
+ PyObject *args) // arguments
+{
+ char *executableName, *iconName, *data, *iconData;
+ GRPICONDIR *groupIconDir;
+ DWORD resourceSize;
+ ICONDIR *iconDir;
+ BOOL succeeded;
+ HANDLE handle;
+ int i;
+
+ if (!PyArg_ParseTuple(args, "ss", &executableName, &iconName))
+ return NULL;
+
+ // begin updating the executable
+ handle = BeginUpdateResource(executableName, FALSE);
+ if (!handle) {
+ PyErr_SetExcFromWindowsErrWithFilename(PyExc_WindowsError,
+ GetLastError(), executableName);
+ return NULL;
+ }
+
+ // first attempt to get the data from the icon file
+ data = NULL;
+ succeeded = TRUE;
+ groupIconDir = NULL;
+ if (GetFileData(iconName, &data) < 0)
+ succeeded = FALSE;
+ iconDir = (ICONDIR*) data;
+
+ // next, attempt to add a group icon resource
+ if (succeeded) {
+ groupIconDir = CreateGroupIconResource(iconDir, &resourceSize);
+ if (groupIconDir)
+ succeeded = UpdateResource(handle, RT_GROUP_ICON,
+ MAKEINTRESOURCE(1),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
+ groupIconDir, resourceSize);
+ else succeeded = FALSE;
+ }
+
+ // next, add each icon as a resource
+ if (succeeded) {
+ for (i = 0; i < iconDir->idCount; i++) {
+ iconData = &data[iconDir->idEntries[i].dwImageOffset];
+ resourceSize = iconDir->idEntries[i].dwBytesInRes;
+ succeeded = UpdateResource(handle, RT_ICON, MAKEINTRESOURCE(i + 1),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), iconData,
+ resourceSize);
+ if (!succeeded)
+ break;
+ }
+ }
+
+ // finish writing the resource (or discarding the changes upon an error)
+ if (!EndUpdateResource(handle, !succeeded)) {
+ if (succeeded) {
+ succeeded = FALSE;
+ PyErr_SetExcFromWindowsErrWithFilename(PyExc_WindowsError,
+ GetLastError(), executableName);
+ }
+ }
+
+ // clean up
+ if (groupIconDir)
+ PyMem_Free(groupIconDir);
+ if (data)
+ PyMem_Free(data);
+ if (!succeeded)
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+//-----------------------------------------------------------------------------
+// ExtBeginUpdateResource()
+// Wrapper for BeginUpdateResource().
+//-----------------------------------------------------------------------------
+static PyObject *ExtBeginUpdateResource(
+ PyObject *self, // passthrough argument
+ PyObject *args) // arguments
+{
+ BOOL deleteExistingResources;
+ char *fileName;
+ HANDLE handle;
+
+ deleteExistingResources = TRUE;
+ if (!PyArg_ParseTuple(args, "s|i", &fileName, &deleteExistingResources))
+ return NULL;
+ handle = BeginUpdateResource(fileName, deleteExistingResources);
+ if (!handle) {
+ PyErr_SetExcFromWindowsErrWithFilename(PyExc_WindowsError,
+ GetLastError(), fileName);
+ return NULL;
+ }
+ return PyInt_FromLong((long) handle);
+}
+
+
+//-----------------------------------------------------------------------------
+// ExtUpdateResource()
+// Wrapper for UpdateResource().
+//-----------------------------------------------------------------------------
+static PyObject *ExtUpdateResource(
+ PyObject *self, // passthrough argument
+ PyObject *args) // arguments
+{
+ int resourceType, resourceId, resourceDataSize;
+ char *resourceData;
+ HANDLE handle;
+
+ if (!PyArg_ParseTuple(args, "iiis#", &handle, &resourceType, &resourceId,
+ &resourceData, &resourceDataSize))
+ return NULL;
+ if (!UpdateResource(handle, MAKEINTRESOURCE(resourceType),
+ MAKEINTRESOURCE(resourceId),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), resourceData,
+ resourceDataSize)) {
+ PyErr_SetExcFromWindowsErr(PyExc_WindowsError, GetLastError());
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+//-----------------------------------------------------------------------------
+// ExtEndUpdateResource()
+// Wrapper for EndUpdateResource().
+//-----------------------------------------------------------------------------
+static PyObject *ExtEndUpdateResource(
+ PyObject *self, // passthrough argument
+ PyObject *args) // arguments
+{
+ BOOL discardChanges;
+ HANDLE handle;
+
+ discardChanges = FALSE;
+ if (!PyArg_ParseTuple(args, "i|i", &handle, &discardChanges))
+ return NULL;
+ if (!EndUpdateResource(handle, discardChanges)) {
+ PyErr_SetExcFromWindowsErr(PyExc_WindowsError, GetLastError());
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+//-----------------------------------------------------------------------------
+// ExtGetDependentFiles()
+// Return a list of files that this file depends on.
+//-----------------------------------------------------------------------------
+static PyObject *ExtGetDependentFiles(
+ PyObject *self, // passthrough argument
+ PyObject *args) // arguments
+{
+ PyObject *results;
+ char *imageName;
+
+ if (!PyArg_ParseTuple(args, "s", &imageName))
+ return NULL;
+ g_ImageNames = PyDict_New();
+ if (!g_ImageNames)
+ return NULL;
+ if (!BindImageEx(BIND_NO_BOUND_IMPORTS | BIND_NO_UPDATE | BIND_ALL_IMAGES,
+ imageName, NULL, NULL, BindStatusRoutine)) {
+ Py_DECREF(g_ImageNames);
+ PyErr_SetExcFromWindowsErrWithFilename(g_BindErrorException,
+ GetLastError(), imageName);
+ return NULL;
+ }
+ results = PyDict_Keys(g_ImageNames);
+ Py_DECREF(g_ImageNames);
+ return results;
+}
+
+
+//-----------------------------------------------------------------------------
+// ExtGetSystemDir()
+// Return the Windows directory (C:\Windows for example).
+//-----------------------------------------------------------------------------
+static PyObject *ExtGetSystemDir(
+ PyObject *self, // passthrough argument
+ PyObject *args) // arguments (ignored)
+{
+ char dir[MAX_PATH + 1];
+
+ if (GetSystemDirectory(dir, sizeof(dir)))
+ return PyString_FromString(dir);
+ PyErr_SetExcFromWindowsErr(PyExc_RuntimeError, GetLastError());
+ return NULL;
+}
+#endif
+
+
+//-----------------------------------------------------------------------------
+// ExtSetOptimizeFlag()
+// Set the optimize flag as needed.
+//-----------------------------------------------------------------------------
+static PyObject *ExtSetOptimizeFlag(
+ PyObject *self, // passthrough argument
+ PyObject *args) // arguments
+{
+ if (!PyArg_ParseTuple(args, "i", &Py_OptimizeFlag))
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods
+//-----------------------------------------------------------------------------
+static PyMethodDef g_ModuleMethods[] = {
+ { "SetOptimizeFlag", ExtSetOptimizeFlag, METH_VARARGS },
+#ifdef WIN32
+ { "BeginUpdateResource", ExtBeginUpdateResource, METH_VARARGS },
+ { "UpdateResource", ExtUpdateResource, METH_VARARGS },
+ { "EndUpdateResource", ExtEndUpdateResource, METH_VARARGS },
+ { "AddIcon", ExtAddIcon, METH_VARARGS },
+ { "GetDependentFiles", ExtGetDependentFiles, METH_VARARGS },
+ { "GetSystemDir", ExtGetSystemDir, METH_NOARGS },
+#endif
+ { NULL }
+};
+
+
+//-----------------------------------------------------------------------------
+// initutil()
+// Initialization routine for the shared libary.
+//-----------------------------------------------------------------------------
+void initutil(void)
+{
+ PyObject *module;
+
+ module = Py_InitModule("cx_Freeze.util", g_ModuleMethods);
+ if (!module)
+ return;
+#ifdef WIN32
+ g_BindErrorException = PyErr_NewException("cx_Freeze.util.BindError",
+ NULL, NULL);
+ if (!g_BindErrorException)
+ return;
+ if (PyModule_AddObject(module, "BindError", g_BindErrorException) < 0)
+ return;
+#endif
+}
+
diff --git a/installer/linux/freeze.py b/installer/linux/freeze.py
index ca11e8d5c4..7fa6e4bbd6 100644
--- a/installer/linux/freeze.py
+++ b/installer/linux/freeze.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from __future__ import with_statement
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
@@ -6,162 +7,212 @@ __docformat__ = 'restructuredtext en'
'''
Create linux binary.
'''
-import glob, sys, subprocess, tarfile, os, re, py_compile, shutil
-HOME = '/home/kovid'
-PYINSTALLER = os.path.expanduser('~/build/pyinstaller')
-CALIBREPREFIX = '___'
-PDFTOHTML = '/usr/bin/pdftohtml'
-LIBUNRAR = '/usr/lib/libunrar.so'
-QTDIR = '/usr/lib/qt4'
-QTDLLS = ('QtCore', 'QtGui', 'QtNetwork', 'QtSvg', 'QtXml', 'QtWebKit')
-EXTRAS = ('/usr/lib/python2.5/site-packages/PIL', os.path.expanduser('~/ipython/IPython'))
-SQLITE = '/usr/lib/libsqlite3.so.0'
-DBUS = '/usr/lib/libdbus-1.so.3'
-LIBMNG = '/usr/lib/libmng.so.1'
-LIBZ = '/lib/libz.so.1'
-LIBBZ2 = '/lib/libbz2.so.1'
-LIBUSB = '/usr/lib/libusb.so'
-LIBPOPPLER = '/usr/lib/libpoppler.so.3'
-LIBXML2 = '/usr/lib/libxml2.so.2'
-LIBXSLT = '/usr/lib/libxslt.so.1'
-LIBEXSLT = '/usr/lib/libexslt.so.0'
+def freeze():
+ import glob, sys, subprocess, tarfile, os, re, textwrap, shutil, cStringIO, bz2, codecs
+ from contextlib import closing
+ from cx_Freeze import Executable, setup
+ from calibre.constants import __version__, __appname__
+ from calibre.linux import entry_points
+ from calibre import walk
+ from calibre.web.feeds.recipes import recipe_modules
+ import calibre
+
-CALIBRESRC = os.path.join(CALIBREPREFIX, 'src')
-CALIBREPLUGINS = os.path.join(CALIBRESRC, 'calibre', 'plugins')
+ QTDIR = '/usr/lib/qt4'
+ QTDLLS = ('QtCore', 'QtGui', 'QtNetwork', 'QtSvg', 'QtXml', 'QtWebKit')
+
+ binary_excludes = ['libGLcore*', 'libGL*', 'libnvidia*']
+
+ binary_includes = [
+ '/usr/bin/pdftohtml',
+ '/usr/lib/libunrar.so',
+ '/usr/lib/libsqlite3.so.0',
+ '/usr/lib/libsqlite3.so.0',
+ '/usr/lib/libmng.so.1',
+ '/lib/libz.so.1',
+ '/lib/libbz2.so.1',
+ '/lib/libbz2.so.1',
+ '/usr/lib/libpoppler.so.4',
+ '/usr/lib/libxml2.so.2',
+ '/usr/lib/libxslt.so.1',
+ '/usr/lib/libxslt.so.1'
+ ]
+
+ binary_includes += [os.path.join(QTDIR, 'lib%s.so.4'%x) for x in QTDLLS]
+
+
+ d = os.path.dirname
+ CALIBRESRC = d(d(d(os.path.abspath(calibre.__file__))))
+ CALIBREPLUGINS = os.path.join(CALIBRESRC, 'src', 'calibre', 'plugins')
+ FREEZE_DIR = os.path.join(CALIBRESRC, 'build', 'cx_freeze')
+ DIST_DIR = os.path.join(CALIBRESRC, 'dist')
+
+ os.chdir(CALIBRESRC)
+
+ print 'Freezing calibre located at', CALIBRESRC
+
+ sys.path.insert(0, os.path.join(CALIBRESRC, 'src'))
+
+ entry_points = entry_points['console_scripts'] + entry_points['gui_scripts']
+ entry_points = ['calibre_postinstall=calibre.linux:binary_install',
+ 'calibre-parallel=calibre.parallel:main'] + entry_points
+ executables = {}
+ for ep in entry_points:
+ executables[ep.split('=')[0].strip()] = (ep.split('=')[1].split(':')[0].strip(),
+ ep.split(':')[-1].strip())
+
+ if os.path.exists(FREEZE_DIR):
+ shutil.rmtree(FREEZE_DIR)
+ os.makedirs(FREEZE_DIR)
+
+ if not os.path.exists(DIST_DIR):
+ os.makedirs(DIST_DIR)
+
+ includes = [x[0] for x in executables.values()]
+
+ excludes = ['matplotlib', "Tkconstants", "Tkinter", "tcl", "_imagingtk",
+ "ImageTk", "FixTk", 'wx', 'PyQt4.QtAssistant', 'PyQt4.QtOpenGL.so',
+ 'PyQt4.QtScript.so', 'PyQt4.QtSql.so', 'PyQt4.QtTest.so', 'qt',
+ 'glib', 'gobject']
+
+ packages = ['calibre', 'encodings', 'cherrypy', 'cssutils', 'xdg']
+
+ includes += ['calibre.web.feeds.recipes.'+r for r in recipe_modules]
+
+ LOADER = '/tmp/loader.py'
+ open(LOADER, 'wb').write('# This script is never actually used.\nimport sys')
+
+ INIT_SCRIPT = '/tmp/init.py'
+ open(INIT_SCRIPT, 'wb').write(textwrap.dedent('''
+ ## Load calibre module specified in the environment variable CALIBRE_CX_EXE
+ ## Also restrict sys.path to the executables' directory and add the
+ ## executables directory to LD_LIBRARY_PATH
+ import encodings
+ import os
+ import sys
+ import warnings
+ import zipimport
+ import locale
+ import codecs
+
+ enc = locale.getdefaultlocale()[1]
+ if not enc:
+ enc = locale.nl_langinfo(locale.CODESET)
+ enc = codecs.lookup(enc if enc else 'UTF-8').name
+ sys.setdefaultencoding(enc)
+
+ paths = os.environ.get('LD_LIBRARY_PATH', '').split(os.pathsep)
+ if DIR_NAME not in paths or not sys.getfilesystemencoding():
+ paths.insert(0, DIR_NAME)
+ os.environ['LD_LIBRARY_PATH'] = os.pathsep.join(paths)
+ os.environ['PYTHONIOENCODING'] = enc
+ os.execv(sys.executable, sys.argv)
+
+ sys.path = sys.path[:3]
+ sys.frozen = True
+ sys.frozen_path = DIR_NAME
+
+ executables = %(executables)s
+
+ exe = os.environ.get('CALIBRE_CX_EXE', False)
+ ret = 1
+ if not exe:
+ print >>sys.stderr, 'Invalid invocation of calibre loader. CALIBRE_CX_EXE not set'
+ elif exe not in executables:
+ print >>sys.stderr, 'Invalid invocation of calibre loader. CALIBRE_CX_EXE=%%s is unknown'%%exe
+ else:
+ sys.argv[0] = exe
+ module, func = executables[exe]
+ module = __import__(module, fromlist=[1])
+ func = getattr(module, func)
+ ret = func()
+
+ module = sys.modules.get("threading")
+ if module is not None:
+ module._shutdown()
+ sys.exit(ret)
+ ''')%dict(executables=repr(executables)))
+ sys.argv = ['freeze', 'build_exe']
+ setup(
+ name = __appname__,
+ version = __version__,
+ executables = [Executable(script=LOADER, targetName='loader', compress=False)],
+ options = { 'build_exe' :
+ {
+ 'build_exe' : os.path.join(CALIBRESRC, 'build/cx_freeze'),
+ 'optimize' : 2,
+ 'excludes' : excludes,
+ 'includes' : includes,
+ 'packages' : packages,
+ 'init_script' : INIT_SCRIPT,
+ 'copy_dependent_files' : True,
+ 'create_shared_zip' : False,
+ }
+ }
+ )
+
+ def copy_binary(src, dest_dir):
+ dest = os.path.join(dest_dir, os.path.basename(src))
+ if not os.path.exists(dest_dir):
+ os.makedirs(dest_dir)
+ shutil.copyfile(src, dest)
+ shutil.copymode(src, dest)
+
+ for f in binary_includes:
+ copy_binary(f, FREEZE_DIR)
+
+ for pat in binary_excludes:
+ matches = glob.glob(os.path.join(FREEZE_DIR, pat))
+ for f in matches:
+ os.remove(f)
+
+ print 'Adding calibre plugins...'
+ os.makedirs(os.path.join(FREEZE_DIR, 'plugins'))
+ for f in glob.glob(os.path.join(CALIBREPLUGINS, '*.so')):
+ copy_binary(f, os.path.join(FREEZE_DIR, 'plugins'))
+
+ print 'Adding Qt plugins...'
+ plugdir = os.path.join(QTDIR, 'plugins')
+ for dirpath, dirnames, filenames in os.walk(plugdir):
+ for f in filenames:
+ if not f.endswith('.so') or 'designer' in dirpath or 'codecs' in dirpath or 'sqldrivers' in dirpath:
+ continue
+ f = os.path.join(dirpath, f)
+ dest_dir = dirpath.replace(plugdir, os.path.join(FREEZE_DIR, 'qtlugins'))
+ copy_binary(f, dest_dir)
-sys.path.insert(0, CALIBRESRC)
-from calibre import __version__
-from calibre.parallel import PARALLEL_FUNCS
-from calibre.web.feeds.recipes import recipes
-hiddenimports = list(map(lambda x: x[0], PARALLEL_FUNCS.values()))
-hiddenimports += ['PyQt4.QtWebKit']
-hiddenimports += ['lxml._elementpath', 'keyword', 'codeop', 'commands', 'shlex', 'pydoc']
-hiddenimports += map(lambda x: x.__module__, recipes)
-open(os.path.join(PYINSTALLER, 'hooks', 'hook-calibre.parallel.py'), 'wb').write('hiddenimports = %s'%repr(hiddenimports))
-
-def run_pyinstaller(args=sys.argv):
- subprocess.check_call(('/usr/bin/sudo', 'chown', '-R', 'kovid:users', glob.glob('/usr/lib/python*/site-packages/')[-1]))
- subprocess.check_call('rm -rf %(py)s/dist/* %(py)s/build/*'%dict(py=PYINSTALLER), shell=True)
- cp = HOME+'/build/'+os.path.basename(os.getcwd())
- spec = open(os.path.join(PYINSTALLER, 'calibre', 'calibre.spec'), 'wb')
- raw = re.sub(r'CALIBREPREFIX\s+=\s+\'___\'', 'CALIBREPREFIX = '+repr(cp),
- open(__file__).read())
- spec.write(raw)
- spec.close()
- os.chdir(PYINSTALLER)
- shutil.rmtree('calibre/dist')
- os.mkdir('calibre/dist')
- subprocess.check_call('python -OO Build.py calibre/calibre.spec', shell=True)
-
+ print 'Creating launchers'
+ for exe in executables:
+ path = os.path.join(FREEZE_DIR, exe)
+ open(path, 'wb').write(textwrap.dedent('''\
+ #!/bin/sh
+ export CALIBRE_CX_EXE=%s
+ path=`readlink -e $0`
+ base=`dirname $path`
+ loader=$base/loader
+ export LD_LIBRARY_PATH=$base:$LD_LIBRARY_PATH
+ $loader "$@"
+ ''')%exe)
+ os.chmod(path, 0755)
+
+ exes = list(executables.keys())
+ exes.remove('calibre_postinstall')
+ exes.remove('calibre-parallel')
+ open(os.path.join(FREEZE_DIR, 'manifest'), 'wb').write('\n'.join(exes))
+
+ print 'Creating archive...'
+ dist = open(os.path.join(DIST_DIR, 'calibre-%s-i686.tar.bz2'%__version__), 'wb')
+ with closing(tarfile.open(fileobj=dist, mode='w:bz2',
+ format=tarfile.PAX_FORMAT)) as tf:
+ for f in walk(FREEZE_DIR):
+ name = f.replace(FREEZE_DIR, '')[1:]
+ if name:
+ tf.add(f, name)
+ dist.flush()
+ dist.seek(0, 2)
+ print 'Archive %s created: %.2f MB'%(dist.name, dist.tell()/(1024.**2))
return 0
-
-if __name__ == '__main__' and 'freeze.py' in __file__:
- sys.exit(run_pyinstaller())
-
-
-loader = os.path.join(os.path.expanduser('~/temp'), 'calibre_installer_loader.py')
-if not os.path.exists(loader):
- open(loader, 'wb').write('''
-import sys, os
-sys.frozen_path = os.getcwd()
-os.chdir(os.environ.get("ORIGWD", "."))
-sys.path.insert(0, os.path.join(sys.frozen_path, "library.pyz"))
-sys.path.insert(0, sys.frozen_path)
-from PyQt4.QtCore import QCoreApplication
-QCoreApplication.setLibraryPaths([sys.frozen_path, os.path.join(sys.frozen_path, "qtplugins")])
-''')
-excludes = ['gtk._gtk', 'gtk.glade', 'qt', 'matplotlib.nxutils', 'matplotlib._cntr',
- 'matplotlib.ttconv', 'matplotlib._image', 'matplotlib.ft2font',
- 'matplotlib._transforms', 'matplotlib._agg', 'matplotlib.backends._backend_agg',
- 'matplotlib.axes', 'matplotlib', 'matplotlib.pyparsing',
- 'TKinter', 'atk', 'gobject._gobject', 'pango', 'PIL', 'Image', 'IPython']
-
-
-sys.path.insert(0, CALIBRESRC)
-from calibre.linux import entry_points
-
-executables, scripts = ['calibre_postinstall', 'calibre-parallel'], \
- [os.path.join(CALIBRESRC, 'calibre', 'linux.py'), os.path.join(CALIBRESRC, 'calibre', 'parallel.py')]
-
-for entry in entry_points['console_scripts'] + entry_points['gui_scripts']:
- fields = entry.split('=')
- executables.append(fields[0].strip())
- scripts.append(os.path.join(CALIBRESRC, *map(lambda x: x.strip(), fields[1].split(':')[0].split('.')))+'.py')
-
-analyses = [Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(HOMEPATH,'support/useUnicode.py'), loader, script],
- pathex=[PYINSTALLER, CALIBRESRC], excludes=excludes) for script in scripts]
-
-pyz = TOC()
-binaries = TOC()
-
-for a in analyses:
- pyz = a.pure + pyz
- binaries = a.binaries + binaries
-pyz = PYZ(pyz, name='library.pyz')
-
-built_executables = []
-for script, exe, a in zip(scripts, executables, analyses):
- built_executables.append(EXE(PYZ(TOC()),
- a.scripts+[('O','','OPTION'),],
- exclude_binaries=1,
- name=os.path.join('buildcalibre', exe),
- debug=False,
- strip=True,
- upx=False,
- excludes=excludes,
- console=1))
-
-print 'Adding plugins...'
-for f in glob.glob(os.path.join(CALIBREPLUGINS, '*.so')):
- binaries += [('plugins/'+os.path.basename(f), f, 'BINARY')]
-for f in glob.glob(os.path.join(CALIBREPLUGINS, '*.so.*')):
- binaries += [(os.path.basename(f), f, 'BINARY')]
-
-print 'Adding external programs...'
-binaries += [('pdftohtml', PDFTOHTML, 'BINARY'),
- ('libunrar.so', LIBUNRAR, 'BINARY')]
-
-print 'Adding external libraries...'
-binaries += [ (os.path.basename(x), x, 'BINARY') for x in (SQLITE, DBUS,
- LIBMNG, LIBZ, LIBBZ2, LIBUSB, LIBPOPPLER, LIBXML2, LIBXSLT, LIBEXSLT)]
-
-
-qt = []
-for dll in QTDLLS:
- path = os.path.join(QTDIR, 'lib'+dll+'.so.4')
- qt.append((os.path.basename(path), path, 'BINARY'))
-binaries += qt
-
-plugins = []
-plugdir = os.path.join(QTDIR, 'plugins')
-for dirpath, dirnames, filenames in os.walk(plugdir):
- for f in filenames:
- if not f.endswith('.so') or 'designer' in dirpath or 'codcs' in dirpath or 'sqldrivers' in dirpath : continue
- f = os.path.join(dirpath, f)
- plugins.append(('qtplugins/'+f.replace(plugdir, ''), f, 'BINARY'))
-binaries += plugins
-
-manifest = '/tmp/manifest'
-open(manifest, 'wb').write('\n'.join(executables))
-version = '/tmp/version'
-open(version, 'wb').write(__version__)
-coll = COLLECT(binaries, pyz,
- [('manifest', manifest, 'DATA'), ('version', version, 'DATA')],
- *built_executables,
- **dict(strip=True,
- upx=False,
- excludes=excludes,
- name='dist'))
-
-os.chdir(os.path.join(HOMEPATH, 'calibre', 'dist'))
-for folder in EXTRAS:
- subprocess.check_call('cp -rf %s .'%folder, shell=True)
-
-print 'Building tarball...'
-tbz2 = 'calibre-%s-i686.tar.bz2'%__version__
-tf = tarfile.open(os.path.join('/tmp', tbz2), 'w:bz2')
-
-for f in os.listdir('.'):
- tf.add(f)
+if __name__ == '__main__':
+ freeze()
diff --git a/installer/osx/freeze.py b/installer/osx/freeze.py
index f40c280570..2a74d15802 100644
--- a/installer/osx/freeze.py
+++ b/installer/osx/freeze.py
@@ -177,7 +177,7 @@ _check_symlinks_prescript()
def fix_python_dependencies(self, files):
for f in files:
- subprocess.check_call(['/usr/bin/install_name_tool', '-change', '/Library/Frameworks/Python.framework/Versions/2.5/Python', '@executable_path/../Frameworks/Python.framework/Versions/2.5/Python', f])
+ subprocess.check_call(['/usr/bin/install_name_tool', '-change', '/Library/Frameworks/Python.framework/Versions/2.6/Python', '@executable_path/../Frameworks/Python.framework/Versions/2.6/Python', f])
def fix_misc_dependencies(self, files):
for path in files:
@@ -247,10 +247,13 @@ _check_symlinks_prescript()
print 'Adding pdftohtml'
os.link(os.path.expanduser('~/pdftohtml'), os.path.join(frameworks_dir, 'pdftohtml'))
print 'Adding plugins'
- module_dir = os.path.join(resource_dir, 'lib', 'python2.5', 'lib-dynload')
+ module_dir = os.path.join(resource_dir, 'lib', 'python2.6', 'lib-dynload')
print 'Adding fontconfig'
for f in glob.glob(os.path.expanduser('~/fontconfig-bundled/*')):
- os.link(f, os.path.join(frameworks_dir, os.path.basename(f)))
+ dest = os.path.join(frameworks_dir, os.path.basename(f))
+ if os.path.exists(dest):
+ os.remove(dest)
+ os.link(f, dest)
dst = os.path.join(resource_dir, 'fonts')
if os.path.exists(dst):
shutil.rmtree(dst)
@@ -258,7 +261,7 @@ _check_symlinks_prescript()
print
print 'Adding IPython'
- dst = os.path.join(resource_dir, 'lib', 'python2.5', 'IPython')
+ dst = os.path.join(resource_dir, 'lib', 'python2.6', 'IPython')
if os.path.exists(dst): shutil.rmtree(dst)
shutil.copytree(os.path.expanduser('~/build/ipython/IPython'), dst)
@@ -280,6 +283,7 @@ _check_symlinks_prescript()
f = open(launcher_path, 'r')
src = f.read()
f.close()
+ src = src.replace('import Image', 'from PIL import Image')
src = re.sub('(_run\s*\(.*?.py.*?\))', cs+'%s'%(
'''
sys.frameworks_dir = os.path.join(os.path.dirname(os.environ['RESOURCEPATH']), 'Frameworks')
@@ -290,7 +294,7 @@ sys.frameworks_dir = os.path.join(os.path.dirname(os.environ['RESOURCEPATH']), '
f.close()
print
print 'Adding main scripts to site-packages'
- f = zipfile.ZipFile(os.path.join(self.dist_dir, APPNAME+'.app', 'Contents', 'Resources', 'lib', 'python2.5', 'site-packages.zip'), 'a', zipfile.ZIP_DEFLATED)
+ f = zipfile.ZipFile(os.path.join(self.dist_dir, APPNAME+'.app', 'Contents', 'Resources', 'lib', 'python2.6', 'site-packages.zip'), 'a', zipfile.ZIP_DEFLATED)
for script in scripts['gui']+scripts['console']:
f.write(script, script.partition('/')[-1])
f.close()
@@ -322,7 +326,8 @@ def main():
'genshi', 'calibre.web.feeds.recipes.*',
'calibre.ebooks.lrf.any.*', 'calibre.ebooks.lrf.feeds.*',
'keyword', 'codeop', 'pydoc', 'readline',
- 'BeautifulSoup'],
+ 'BeautifulSoup'
+ ],
'packages' : ['PIL', 'Authorization', 'lxml'],
'excludes' : ['IPython'],
'plist' : { 'CFBundleGetInfoString' : '''calibre, an E-book management application.'''
diff --git a/installer/windows/freeze.py b/installer/windows/freeze.py
index 007217803e..73bb9cae56 100644
--- a/installer/windows/freeze.py
+++ b/installer/windows/freeze.py
@@ -6,13 +6,13 @@ __docformat__ = 'restructuredtext en'
'''
Freeze app into executable using py2exe.
'''
-QT_DIR = 'C:\\Qt\\4.4.1'
+QT_DIR = 'C:\\Qt\\4.4.3'
LIBUSB_DIR = 'C:\\libusb'
LIBUNRAR = 'C:\\Program Files\\UnrarDLL\\unrar.dll'
PDFTOHTML = 'C:\\pdftohtml\\pdftohtml.exe'
IMAGEMAGICK_DIR = 'C:\\ImageMagick'
FONTCONFIG_DIR = 'C:\\fontconfig'
-
+VC90 = r'C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.CRT'
import sys, os, py2exe, shutil, zipfile, glob, subprocess, re
from distutils.core import setup
@@ -65,6 +65,8 @@ class BuildEXE(py2exe.build_exe.py2exe):
shutil.copyfile(f, os.path.join(self.dist_dir, os.path.basename(f)))
for f in glob.glob(os.path.join(BASE_DIR, 'src', 'calibre', 'plugins', '*.pyd')):
shutil.copyfile(f, os.path.join(tgt, os.path.basename(f)))
+ for f in glob.glob(os.path.join(BASE_DIR, 'src', 'calibre', 'plugins', '*.manifest')):
+ shutil.copyfile(f, os.path.join(tgt, os.path.basename(f)))
shutil.copyfile('LICENSE', os.path.join(self.dist_dir, 'LICENSE'))
print
print 'Adding QtXml4.dll'
@@ -115,12 +117,17 @@ class BuildEXE(py2exe.build_exe.py2exe):
shutil.copytree(f, tgt)
else:
shutil.copyfile(f, tgt)
-
+
print
print 'Doing DLL redirection' # See http://msdn.microsoft.com/en-us/library/ms682600(VS.85).aspx
for f in glob.glob(os.path.join(PY2EXE_DIR, '*.exe')):
open(f + '.local', 'w').write('\n')
+ print
+ print 'Adding Windows runtime dependencies...'
+ for f in glob.glob(os.path.join(VC90, '*')):
+ shutil.copyfile(f, os.path.join(PY2EXE_DIR, os.path.basename(f)))
+
@classmethod
def manifest(cls, prog):
@@ -142,17 +149,17 @@ def main(args=sys.argv):
{'script' : scripts['gui'][0],
'dest_base' : APPNAME,
'icon_resources' : [(1, ICONS[0])],
- 'other_resources' : [BuildEXE.manifest(APPNAME)],
+ #'other_resources' : [BuildEXE.manifest(APPNAME)],
},
{'script' : scripts['gui'][1],
'dest_base' : 'lrfviewer',
'icon_resources' : [(1, ICONS[1])],
- 'other_resources' : [BuildEXE.manifest('lrfviewer')],
+ #'other_resources' : [BuildEXE.manifest('lrfviewer')],
},
{'script' : scripts['gui'][2],
'dest_base' : 'ebook-viewer',
'icon_resources' : [(1, ICONS[1])],
- 'other_resources' : [BuildEXE.manifest('ebook-viewer')],
+ #'other_resources' : [BuildEXE.manifest('ebook-viewer')],
},
],
console = console,
@@ -162,12 +169,12 @@ def main(args=sys.argv):
'includes' : [
'sip', 'pkg_resources', 'PyQt4.QtSvg',
'mechanize', 'ClientForm', 'wmi',
- 'win32file', 'pythoncom', 'rtf2xml',
+ 'win32file', 'pythoncom',
'win32process', 'win32api', 'msvcrt',
'win32event', 'calibre.ebooks.lrf.any.*',
'calibre.ebooks.lrf.feeds.*',
- 'genshi', 'BeautifulSoup',
- 'path', 'pydoc', 'IPython.Extensions.*',
+ 'BeautifulSoup', 'pyreadline',
+ 'pydoc', 'IPython.Extensions.*',
'calibre.web.feeds.recipes.*',
'PyQt4.QtWebKit', 'PyQt4.QtNetwork',
],
diff --git a/pyqtdistutils.py b/pyqtdistutils.py
index 252968fb60..0e53aaabfe 100644
--- a/pyqtdistutils.py
+++ b/pyqtdistutils.py
@@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en'
'''
Build PyQt extensions. Integrates with distutils (but uses the PyQt build system).
'''
-from distutils.core import Extension
+from distutils.core import Extension as _Extension
from distutils.command.build_ext import build_ext as _build_ext
from distutils.dep_util import newer_group
from distutils import log
@@ -15,12 +15,23 @@ import sipconfig, os, sys, string, glob, shutil
from PyQt4 import pyqtconfig
iswindows = 'win32' in sys.platform
QMAKE = os.path.expanduser('~/qt/bin/qmake') if 'darwin' in sys.platform else'qmake'
-WINDOWS_PYTHON = ['C:/Python25/libs']
+WINDOWS_PYTHON = ['C:/Python26/libs']
OSX_SDK = '/Developer/SDKs/MacOSX10.4u.sdk'
def replace_suffix(path, new_suffix):
return os.path.splitext(path)[0] + new_suffix
+class Extension(_Extension):
+ pass
+
+if iswindows:
+ from distutils import msvc9compiler
+ msvc = msvc9compiler.MSVCCompiler()
+ msvc.initialize()
+ nmake = msvc.find_exe('nmake.exe')
+ rc = msvc.find_exe('rc.exe')
+
+
class PyQtExtension(Extension):
def __init__(self, name, sources, sip_sources, **kw):
@@ -37,9 +48,7 @@ class PyQtExtension(Extension):
class build_ext(_build_ext):
def make(self, makefile):
- make = 'make'
- if iswindows:
- make = 'mingw32-make'
+ make = nmake if iswindows else 'make'
self.spawn([make, '-f', makefile])
def build_qt_objects(self, ext, bdir):
@@ -65,12 +74,13 @@ CONFIG += x86 ppc
open(name+'.pro', 'wb').write(pro)
self.spawn([QMAKE, '-o', 'Makefile.qt', name+'.pro'])
self.make('Makefile.qt')
- pat = 'release\\*.o' if iswindows else '*.o'
+ pat = 'release\\*.obj' if iswindows else '*.o'
return map(os.path.abspath, glob.glob(pat))
finally:
os.chdir(cwd)
def build_sbf(self, sip, sbf, bdir):
+ print '\tBuilding spf...'
sip_bin = self.sipcfg.sip_bin
self.spawn([sip_bin,
"-c", bdir,
@@ -100,9 +110,7 @@ CONFIG += x86 ppc
def build_extension(self, ext):
self.inplace = True # Causes extensions to be built in the source tree
- if not isinstance(ext, PyQtExtension):
- return _build_ext.build_extension(self, ext)
-
+
fullname = self.get_ext_fullname(ext.name)
if self.inplace:
# ignore build-lib -- put the compiled extension into
@@ -119,7 +127,38 @@ CONFIG += x86 ppc
else:
ext_filename = os.path.join(self.build_lib,
self.get_ext_filename(fullname))
- bdir = os.path.abspath(os.path.join(self.build_temp, fullname))
+ bdir = os.path.abspath(os.path.join(self.build_temp, fullname))
+ if not os.path.exists(bdir):
+ os.makedirs(bdir)
+
+ if not isinstance(ext, PyQtExtension):
+ if not iswindows:
+ return _build_ext.build_extension(self, ext)
+
+ c_sources = [f for f in ext.sources if os.path.splitext(f)[1].lower() in ('.c', '.cpp', '.cxx')]
+ compile_args = '/c /nologo /Ox /MD /W3 /GX /DNDEBUG'.split()
+ compile_args += ext.extra_compile_args
+ self.swig_opts = ''
+ inc_dirs = self.include_dirs + [x.replace('/', '\\') for x in ext.include_dirs]
+ cc = [msvc.cc] + compile_args + ['-I%s'%x for x in list(set(inc_dirs))]
+ objects = []
+ for f in c_sources:
+ o = os.path.join(bdir, os.path.basename(f)+'.obj')
+ objects.append(o)
+ compiler = cc + ['/Tc'+f, '/Fo'+o]
+ self.spawn(compiler)
+ out = os.path.join(bdir, base+'.pyd')
+ linker = [msvc.linker] + '/DLL /nologo /INCREMENTAL:NO'.split()
+ linker += ['/LIBPATH:'+x for x in self.library_dirs]
+ linker += [x+'.lib' for x in ext.libraries]
+ linker += ['/EXPORT:init'+base] + objects + ['/OUT:'+out]
+ self.spawn(linker)
+ for src in (out, out+'.manifest'):
+ shutil.copyfile(src, os.path.join('src', 'calibre', 'plugins', os.path.basename(src)))
+ return
+
+
+
if not os.path.exists(bdir):
os.makedirs(bdir)
ext.sources2 = map(os.path.abspath, ext.sources)
diff --git a/setup.py b/setup.py
index 37d54c4317..523b2b1509 100644
--- a/setup.py
+++ b/setup.py
@@ -46,10 +46,10 @@ main_functions = {
}
if __name__ == '__main__':
- from setuptools import setup, find_packages, Extension
+ from setuptools import setup, find_packages
from distutils.command.build import build as _build
from distutils.core import Command as _Command
- from pyqtdistutils import PyQtExtension, build_ext
+ from pyqtdistutils import PyQtExtension, build_ext, Extension
import subprocess, glob
def newer(targets, sources):
@@ -391,11 +391,14 @@ if __name__ == '__main__':
ext_modules.append(Extension('calibre.plugins.winutil',
sources=['src/calibre/utils/windows/winutil.c'],
libraries=['shell32', 'setupapi'],
- include_dirs=['C:/WinDDK/6001.18001/inc/api/'])
- )
+ include_dirs=['C:/WinDDK/6001.18001/inc/api/',
+ 'C:/WinDDK/6001.18001/inc/crt/'],
+ extra_compile_args=['/X']
+ ))
if isosx:
ext_modules.append(Extension('calibre.plugins.usbobserver',
- sources=['src/calibre/devices/usbobserver/usbobserver.c'])
+ sources=['src/calibre/devices/usbobserver/usbobserver.c'],
+ extra_link_args=['-framework', 'IOKit'])
)
setup(
diff --git a/src/calibre/__init__.py b/src/calibre/__init__.py
index 0e379ce9d1..f483902126 100644
--- a/src/calibre/__init__.py
+++ b/src/calibre/__init__.py
@@ -20,6 +20,11 @@ mimetypes.add_type('application/epub+zip', '.epub')
mimetypes.add_type('text/x-sony-bbeb+xml', '.lrs')
mimetypes.add_type('application/x-sony-bbeb', '.lrf')
+def to_unicode(raw, encoding='utf-8', errors='strict'):
+ if isinstance(raw, unicode):
+ return raw
+ return raw.decode(encoding, errors)
+
def unicode_path(path, abs=False):
if not isinstance(path, unicode):
path = path.decode(sys.getfilesystemencoding())
@@ -317,7 +322,12 @@ class LoggingInterface:
def ___log(self, func, msg, args, kwargs):
args = [msg] + list(args)
for i in range(len(args)):
- if isinstance(args[i], unicode):
+ if not isinstance(args[i], basestring):
+ continue
+ if sys.version_info[:2] > (2, 5):
+ if not isinstance(args[i], unicode):
+ args[i] = args[i].decode(preferred_encoding, 'replace')
+ elif isinstance(args[i], unicode):
args[i] = args[i].encode(preferred_encoding, 'replace')
func(*args, **kwargs)
diff --git a/src/calibre/constants.py b/src/calibre/constants.py
index f4eb465dde..0bccd77c44 100644
--- a/src/calibre/constants.py
+++ b/src/calibre/constants.py
@@ -2,7 +2,7 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
__appname__ = 'calibre'
-__version__ = '0.4.112'
+__version__ = '0.4.115'
__author__ = "Kovid Goyal "
'''
Various run time constants.
diff --git a/src/calibre/devices/libusb.py b/src/calibre/devices/libusb.py
index 0bedce32bb..226a99f239 100644
--- a/src/calibre/devices/libusb.py
+++ b/src/calibre/devices/libusb.py
@@ -4,17 +4,20 @@ __copyright__ = '2008, Kovid Goyal '
This module provides a thin ctypes based wrapper around libusb.
"""
-from ctypes import cdll, POINTER, byref, pointer, Structure, \
+from ctypes import cdll, POINTER, byref, pointer, Structure as _Structure, \
c_ubyte, c_ushort, c_int, c_char, c_void_p, c_byte, c_uint
from errno import EBUSY, ENOMEM
-from calibre import iswindows, isosx, load_library, isfrozen
+from calibre import iswindows, isosx, load_library
_libusb_name = 'libusb'
PATH_MAX = 511 if iswindows else 1024 if isosx else 4096
if iswindows:
- Structure._pack_ = 1
+ class Structure(_Structure):
+ _pack_ = 1
_libusb_name = 'libusb0'
+else:
+ Structure = _Structure
try:
try:
diff --git a/src/calibre/devices/prs505/driver.py b/src/calibre/devices/prs505/driver.py
index 698a8f2a03..dd4b8d575a 100644
--- a/src/calibre/devices/prs505/driver.py
+++ b/src/calibre/devices/prs505/driver.py
@@ -64,9 +64,11 @@ class PRS505(Device):
-
- %(storage_card)s
- %(deviceclass)s
+
+
+ %(storage_card)s
+ %(deviceclass)s
+
diff --git a/src/calibre/devices/scanner.py b/src/calibre/devices/scanner.py
index 99a50020ec..40573114a7 100644
--- a/src/calibre/devices/scanner.py
+++ b/src/calibre/devices/scanner.py
@@ -43,7 +43,8 @@ class DeviceScanner(object):
if iswindows:
for device_id in self.devices:
vid, pid = 'vid_%4.4x'%device.VENDOR_ID, 'pid_%4.4x'%device.PRODUCT_ID
- if vid in device_id and pid in device_id:
+ rev = ('rev_%4.4x'%device.BCD).replace('a', ':') # Bug in winutil.get_usb_devices converts a to :
+ if vid in device_id and pid in device_id and rev in device_id:
return True
return False
else:
diff --git a/src/calibre/ebooks/epub/from_html.py b/src/calibre/ebooks/epub/from_html.py
index ae2fa5eae1..66a3cebbae 100644
--- a/src/calibre/ebooks/epub/from_html.py
+++ b/src/calibre/ebooks/epub/from_html.py
@@ -48,8 +48,7 @@ from calibre.ebooks.epub import initialize_container, PROFILES
from calibre.ebooks.epub.split import split
from calibre.ebooks.epub.fonts import Rationalizer
from calibre.constants import preferred_encoding
-from calibre import walk
-from calibre import CurrentDir
+from calibre import walk, CurrentDir, to_unicode
content = functools.partial(os.path.join, u'content')
@@ -79,7 +78,7 @@ def check(opf_path, pretty_print):
base = os.path.dirname(path)
root = html.fromstring(open(content(path), 'rb').read())
for element, attribute, link, pos in list(root.iterlinks()):
- link = link.decode('utf-8')
+ link = to_unicode(link)
plink = Link(link, base)
bad = False
if plink.path is not None and not os.path.exists(plink.path):
@@ -204,7 +203,7 @@ TITLEPAGE = '''\
-

+