[Pymoul-svn] SF.net SVN: pymoul: [61] pymoul/trunk/distutils_upx.py
Status: Alpha
Brought to you by:
tiran
|
From: <ti...@us...> - 2007-01-23 17:51:37
|
Revision: 61
http://pymoul.svn.sourceforge.net/pymoul/?rev=61&view=rev
Author: tiran
Date: 2007-01-23 09:51:37 -0800 (Tue, 23 Jan 2007)
Log Message:
-----------
Modified Paths:
--------------
pymoul/trunk/distutils_upx.py
Modified: pymoul/trunk/distutils_upx.py
===================================================================
--- pymoul/trunk/distutils_upx.py 2007-01-23 13:49:43 UTC (rev 60)
+++ pymoul/trunk/distutils_upx.py 2007-01-23 17:51:37 UTC (rev 61)
@@ -8,19 +8,11 @@
import sys
from inspect import getmro
from tempfile import TemporaryFile
-from subprocess import call
+from subprocess import call as subcall
from distutils import log
from stat import ST_SIZE
+from fnmatch import fnmatch
-def inEnvPath(name):
- result = []
- for path in os.environ['PATH'].split(';'):
- upx = os.path.join(path, name)
- if os.path.isfile(upx):
- result.append(upx)
- if result:
- return result[0]
-
def _call(cmd, silent=False, *args, **kwargs):
"""Call silently - redirect stdout to dump
"""
@@ -30,97 +22,136 @@
else:
stdout = None
try:
- retcode = call(cmd, stdout=stdout, *args, **kwargs)
+ retcode = subcall(cmd, stdout=stdout, *args, **kwargs)
finally:
if stdout:
data = stdout.read()
stdout.close()
return retcode, data
-def _has_upx(upx):
- """Search for UPX in search path
+class UpxCommand:
+ """Upx packer mixin class for distutils
+
+ Usage:
+ class UpxPy2exe(UpxCommand, py2exe):
+ pass
+
+ setup(..., cmdclass = {'py2exe': UpxPy2exe})
+
+ The mixin class should work for every distutils Command based class on
+ every os (Win32, Mac, Linux).
+
+ New options:
+ o upx - True/False
+ o upx_args - additional args for upx (e.g. "--no-color --best")
+ o upx_path - path to upx if not in os.environ['PATH']
+ o upx_extensions - list of extensions to packed (e.g. ['dll','pyd','exe'])
+ o upx_ignore - list of pattern to ignore (e.g. ['python*.dll']=
"""
- try:
- retcode, stdout = _call("%s --version" % upx, silent=True)
- except OSError:
- log.debug('UPX not found')
- return False
- else:
- if retcode == 0:
- log.debug('UPX found')
- return True
- else:
- log.debug('UPX: an error occured %i' % retcode)
- return False
-
-def _upx_compress(upx, args, fname):
- """Check file
- """
- retcode, stdout = _call('upx %s "%s"' % (args, fname), silent=False)
- if retcode == 0: # file packed
- pass
- elif retcode == 2: # file already packed
- pass
- else: # something bad has happend
- sys.exit(retcode)
-
-def otherclass(mycls):
- for cls in getmro(mycls):
- if not issubclass(cls, UpxCommand):
- return cls
- raise ValueError(mycls)
-
-class UpxCommand:
+
def initialize_options(self):
- result = otherclass(self.__class__).initialize_options(self)
+ result = self._otherclass().initialize_options(self)
self.upx = True
self.upx_args = '--no-color --best'
self.upx_path = 'upx'
- self.upx_extensions = (
+ self.upx_extensions = [
'pyd', 'dll', 'exe', # Windows
'', 'so', # Linux
'dylib', # Mac OS X
- )
+ ]
+ self.upx_ignore = []
return result
def finalize_options(self):
- result = otherclass(self.__class__).finalize_options(self)
- self.has_upx = _has_upx(self.upx_path)
- self.upx_packed = []
+ result = self._otherclass().finalize_options(self)
+ self.has_upx = self._upxAvailable()
+ self.upx_packlist = []
return result
-
+
def copy_file(self, *args, **kwargs):
# Override to UPX copied binaries.
- result = otherclass(self.__class__).copy_file(self, *args, **kwargs)
- self._upx_compress(result)
+ result = self._otherclass().copy_file(self, *args, **kwargs)
+ self.upx_packlist.append(result)
return result
- def _upx_compress(self, result):
- fname, copied = result
- if not self.has_upx or not self.upx or not copied:
- return
-
- basename = os.path.basename(fname)
- tmp, ext = os.path.splitext(basename)
- ext = ext[1:] # strip leading dot
- origsize = os.stat(fname)[ST_SIZE]
- if ext in self.upx_extensions:
- _upx_compress(self.upx_path, self.upx_args, os.path.normpath(fname))
- newsize = os.stat(fname)[ST_SIZE]
- ratio = newsize*100 / origsize
- self.upx_packed.append((basename, origsize, newsize, ratio))
- return result
-
def run(self, *args, **kwargs):
- result = otherclass(self.__class__).run(self, *args, **kwargs)
- if self.has_upx and self.upx:
- print "\n*** UPX result ***"
- for basename, origsize, newsize, ratio in self.upx_packed:
- print " %s packed to %i%%" % (basename, ratio)
- print "\n"
+ result = self._otherclass().run(self, *args, **kwargs)
+ self._upxPack()
return result
+ def _upxPack(self):
+ if not self.has_upx or not self.upx:
+ return
+
+ packed = []
+ for fname, copied in self.upx_packlist:
+ if not copied:
+ continue
+ basename = os.path.basename(fname)
+ tmp, ext = os.path.splitext(basename)
+ ext = ext[1:] # strip leading dot
+
+ # check extension
+ if ext not in self.upx_extensions:
+ continue
+ # check ignores
+ if self.upx_ignore:
+ matches = [pat for pat in self.upx_ignore if fnmatch(basename, pat)]
+ if matches:
+ continue
+
+ origsize = os.stat(fname)[ST_SIZE]
+ self._upxPackFile(os.path.normpath(fname))
+ newsize = os.stat(fname)[ST_SIZE]
+ ratio = newsize*100 / origsize
+ packed.append((basename, origsize, newsize, ratio))
+
+ print "\n*** UPX result ***"
+ for basename, origsize, newsize, ratio in packed:
+ print " %s packed to %i%%" % (basename, ratio)
+ if not packed:
+ print " no files packed"
+ print "\n"
+ def _upxPackFile(self, fname):
+ """Pack a file
+ """
+ retcode, stdout = _call('%s %s "%s"' % (self.upx_path, self.upx_args, fname), silent=False)
+ if retcode == 0: # OK, file packed
+ pass
+ elif retcode == 2: # OK, file already packed
+ pass
+ else: # something bad has happend
+ sys.exit(retcode) # XXX
+
+ def _upxAvailable(self):
+ """Search for UPX in search path
+ """
+ try:
+ retcode, stdout = _call("%s --version" % self.upx_path, silent=True)
+ except OSError:
+ log.debug('UPX not found')
+ return False
+ else:
+ if retcode == 0:
+ log.debug('UPX found')
+ return True
+ else:
+ log.debug('UPX: an error occured %i' % retcode)
+ return False
+
+ @classmethod
+ def _otherclass(cls):
+ """Workaround: distutils.cmd.Command is an old style class
+
+ Find next class in MRO that is not based on UpxCommand class
+ """
+ for c in getmro(cls):
+ if not issubclass(c, UpxCommand):
+ return c
+ raise ValueError(cls)
+
+
try:
from py2exe.build_exe import py2exe
except ImportError:
@@ -128,3 +159,4 @@
else:
class UpxPy2exe(UpxCommand, py2exe):
pass
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|