mirror of
https://github.com/kennethreitz-archive/pyinstaller.git
synced 2026-06-05 23:50:17 +00:00
Complete runtime support for .egg-files.
Now Build.py automatically adds a runtime hook whenever a .egg file is packaged. This hook adds the .egg to sys.path at startup, so that it is picked up by the import hooks. In one-dir mode, .eggs files are packaged into a "eggs" subdirectory. In one-file mode, .eggs files are within the executable, and extracted at startup in the temporary directory. I removed the old runtime hook by Hartmut which decompressed .eggs to disk because it is not required anymore since we directly use zipimport to access .eggs. git-svn-id: http://svn.pyinstaller.org/trunk@772 8dd32b29-ccff-0310-8a9a-9233e24343b1
This commit is contained in:
@@ -279,9 +279,9 @@ class Analysis(Target):
|
||||
def assemble(self):
|
||||
print "running Analysis", os.path.basename(self.out)
|
||||
# Reset seen variable to correctly discover dependencies
|
||||
# if there are multiple Analysis in a single specfile.
|
||||
# if there are multiple Analysis in a single specfile.
|
||||
bindepend.seen = {}
|
||||
|
||||
|
||||
paths = self.pathex
|
||||
for i in range(len(paths)):
|
||||
# FIXME: isn't self.pathex already norm-abs-pathed?
|
||||
@@ -334,7 +334,7 @@ class Analysis(Target):
|
||||
if isinstance(mod, mf.ExtensionModule):
|
||||
binaries.append((mod.__name__, fnm, 'EXTENSION'))
|
||||
elif isinstance(mod, (mf.PkgInZipModule, mf.PyInZipModule)):
|
||||
zipfiles.append((os.path.basename(str(mod.owner)),
|
||||
zipfiles.append(("eggs/" + os.path.basename(str(mod.owner)),
|
||||
str(mod.owner), 'ZIPFILE'))
|
||||
else:
|
||||
# mf.PyModule instances expose a list of binary
|
||||
@@ -346,6 +346,8 @@ class Analysis(Target):
|
||||
binaries.extend(bindepend.Dependencies(binaries,
|
||||
platform=target_platform))
|
||||
self.fixMissingPythonLib(binaries)
|
||||
if zipfiles:
|
||||
scripts[-1:-1] = [("_pyi_egg_install.py", os.path.join(HOMEPATH, "support/_pyi_egg_install.py"), 'PYSOURCE')]
|
||||
# Add realtime hooks just before the last script (which is
|
||||
# the entrypoint of the application).
|
||||
scripts[-1:-1] = rthooks
|
||||
|
||||
@@ -333,7 +333,7 @@ int openArchive()
|
||||
filelen = findDigitalSignature();
|
||||
if (filelen < 1)
|
||||
return -1;
|
||||
/* The digital signature has been aligned to 8-bytes boundary.
|
||||
/* The digital signature has been aligned to 8-bytes boundary.
|
||||
We need to look for our cookie taking into account some
|
||||
padding. */
|
||||
for (i = 0; i < 8; ++i)
|
||||
@@ -871,7 +871,7 @@ unsigned char *extract(TOC *ptoc)
|
||||
block_size = PI_PyInt_AsLong(PI_PyDict_GetItemString(aes_dict, "block_size"));
|
||||
iv = malloc(block_size);
|
||||
memset(iv, 0, block_size);
|
||||
|
||||
|
||||
aes_obj = PI_PyObject_CallFunction(func_new, "s#Os#",
|
||||
data, 32,
|
||||
PI_PyDict_GetItemString(aes_dict, "MODE_CFB"),
|
||||
@@ -996,7 +996,7 @@ int extractBinaries(char **workpath)
|
||||
workpath[0] = '\0';
|
||||
VS("Extracting binaries\n");
|
||||
while (ptoc < f_tocend) {
|
||||
if (ptoc->typcd == 'b' || ptoc->typcd == 'x')
|
||||
if (ptoc->typcd == 'b' || ptoc->typcd == 'x' || ptoc->typcd == 'Z')
|
||||
if (extract2fs(ptoc))
|
||||
return -1;
|
||||
ptoc = incrementTocPtr(ptoc);
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Make .eggs and zipfiles available at runtime
|
||||
#
|
||||
# Copyright (C) 2008 Hartmut Goebel <h.goebel@goebel-consult.de>
|
||||
# Licence: GNU General Public License version 3 (GPL v3)
|
||||
#
|
||||
# This file is part of PyInstaller <http://www.pyinstaller.org>
|
||||
#
|
||||
# pyinstaller is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pyinstaller is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
from tempfile import mkstemp
|
||||
|
||||
import carchive
|
||||
|
||||
MEIDIR = os.environ['_MEIPASS2']
|
||||
|
||||
def extract_resource(zip_path):
|
||||
if zip_path in index:
|
||||
# 'directory' entry: recursivly extract all member
|
||||
for name in index[zip_path]:
|
||||
last = extract_resource(os.path.join(zip_path, name))
|
||||
# return the real extracted directory name
|
||||
return os.path.dirname(last)
|
||||
|
||||
# 'file' entry: extract it
|
||||
try:
|
||||
real_path = os.path.join(MEIDIR, *zip_path.split(os.sep))
|
||||
|
||||
if os.path.isfile(real_path):
|
||||
stat = os.stat(real_path)
|
||||
size = content[zip_path][1]
|
||||
if stat.st_size==size: # and stat.st_mtime==timestamp:
|
||||
# size and stamp match, don't bother extracting
|
||||
return real_path
|
||||
|
||||
outf, tmpnam = mkstemp(".$extract", dir=os.path.dirname(real_path))
|
||||
os.write(outf, archive.extract(zip_path)[1])
|
||||
os.close(outf)
|
||||
try:
|
||||
os.rename(tmpnam, real_path)
|
||||
except os.error:
|
||||
if os.path.isfile(real_path):
|
||||
stat = os.stat(real_path)
|
||||
# todo: check timestamp (compare with sys.executable)
|
||||
if stat.st_size == size:
|
||||
# size and stamp match, somebody did it just ahead of
|
||||
# us, so we're done
|
||||
return real_path
|
||||
elif os.name=='nt': # Windows, del old file and retry
|
||||
unlink(real_path)
|
||||
os.rename(tmpnam, real_path)
|
||||
return real_path
|
||||
raise
|
||||
|
||||
except os.error:
|
||||
# todo: report a user-friendly error
|
||||
raise
|
||||
return real_path
|
||||
|
||||
#---
|
||||
|
||||
archive = carchive.CArchive(sys.executable)
|
||||
archive.loadtoc()
|
||||
|
||||
# get contents of archive in a format more suitable for us
|
||||
# list only zipfiles (typcd 'Z') and eggs (typcd 'E')
|
||||
contents = dict([(path, (typcd, ulen))
|
||||
for (dpos, dlen, ulen, flag, typcd, path) in archive.toc
|
||||
if typcd in 'EZ'])
|
||||
|
||||
# build index for recursivly extracting directories
|
||||
index = {}
|
||||
for path in contents:
|
||||
parts = path.split(os.sep)
|
||||
while parts:
|
||||
parent = os.sep.join(parts[:-1])
|
||||
if parent in index:
|
||||
index[parent].append(parts[-1])
|
||||
break
|
||||
else:
|
||||
index[parent] = [parts.pop()]
|
||||
|
||||
# Add the zipfiles to sys.path
|
||||
for zip_path, (typcd, ulen) in contents.items():
|
||||
sys.path.append(extract_resource(zip_path))
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Make .eggs and zipfiles available at runtime
|
||||
#
|
||||
# Copyright (C) 2010 Giovanni Bajo <rasky@develer.com>
|
||||
#
|
||||
# This file is part of PyInstaller <http://www.pyinstaller.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# In addition to the permissions in the GNU General Public License, the
|
||||
# authors give you unlimited permission to link or embed the compiled
|
||||
# version of this file into combinations with other programs, and to
|
||||
# distribute those combinations without any restriction coming from the
|
||||
# use of this file. (The General Public License restrictions do apply in
|
||||
# other respects; for example, they cover modification of the file, and
|
||||
# distribution when not linked into a combine executable.)
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
import os
|
||||
|
||||
d = "eggs"
|
||||
if "_MEIPASS2" in os.environ:
|
||||
d = os.path.join(os.environ["_MEIPASS2"], d)
|
||||
else:
|
||||
d = os.path.join(os.path.dirname(sys.argv[0]), d)
|
||||
|
||||
for fn in os.listdir(d):
|
||||
sys.path.append(os.path.join(d, fn))
|
||||
print "adding", sys.path[-1]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user