[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. |