mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-10-30 18:22:25 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			618 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			618 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python
 | |
| # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
 | |
| from __future__ import with_statement
 | |
| 
 | |
| __license__   = 'GPL v3'
 | |
| __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
 | |
| __docformat__ = 'restructuredtext en'
 | |
| 
 | |
| import sys, os, shutil, plistlib, subprocess, glob, zipfile, tempfile, \
 | |
|     py_compile, stat, operator
 | |
| abspath, join, basename = os.path.abspath, os.path.join, os.path.basename
 | |
| 
 | |
| l = {}
 | |
| exec open('setup.py').read() in l
 | |
| VERSION = l['VERSION']
 | |
| APPNAME = l['APPNAME']
 | |
| scripts = l['scripts']
 | |
| basenames = l['basenames']
 | |
| main_functions = l['main_functions']
 | |
| main_modules = l['main_modules']
 | |
| LICENSE = open('LICENSE', 'rb').read()
 | |
| ENV = dict(
 | |
|         PYTHONPATH='@executable_path/../Resources/Python/site-packages',
 | |
|         PYTHONHOME='@executable_path/../Resources/Python',
 | |
|         FC_CONFIG_DIR='@executable_path/../Resources/fonts',
 | |
|         MAGICK_HOME='@executable_path/../Frameworks/ImageMagick',
 | |
|         QT_PLUGIN_PATH='@executable_path/../MacOS',
 | |
|         PYTHONDONTWRITEBYTECODE='1',
 | |
|         PYTHONIOENCODING='utf-8:replace',
 | |
|         PYTHONOPTIMIZE='2',
 | |
|         )
 | |
| 
 | |
| SW = os.environ.get('SW', '/sw')
 | |
| 
 | |
| def compile_launchers(contents_dir, xprograms):
 | |
|     gcc = os.environ.get('CC', 'gcc')
 | |
|     base = os.path.dirname(__file__)
 | |
|     src = open(join(base, 'launcher.c'), 'rb').read()
 | |
|     env, env_vals = [], []
 | |
|     for key, val in ENV.items():
 | |
|         env.append('"%s"'% key)
 | |
|         env_vals.append('"%s"'% val)
 | |
|     env = ', '.join(env)+', '
 | |
|     env_vals = ', '.join(env_vals)+', '
 | |
|     src = src.replace('/*ENV_VARS*/', env)
 | |
|     src = src.replace('/*ENV_VAR_VALS*/', env_vals)
 | |
|     programs = []
 | |
|     for program, module in xprograms.items():
 | |
|         print '\tCompiling', program
 | |
|         out = join(contents_dir, 'MacOS', program)
 | |
|         programs.append(out)
 | |
|         psrc = src.replace('**PROGRAM**', program)
 | |
|         psrc = psrc.replace('**MODULE**', module)
 | |
|         fsrc = '/tmp/%s.c'%program
 | |
|         with open(fsrc, 'wb') as f:
 | |
|             f.write(psrc)
 | |
|         cmd = [gcc, '-Wall', '-arch', 'x86_64',
 | |
|             '-I%s/python/Python.framework/Headers'%SW,
 | |
|             fsrc, '-o', out, '-F%s/python'%SW,
 | |
|             '-framework', 'Python', '-framework', 'CoreFoundation',
 | |
|             '-headerpad_max_install_names']
 | |
|         print ' '.join(cmd)
 | |
|         sys.stdout.flush()
 | |
|         subprocess.check_call(cmd)
 | |
|     return programs
 | |
| 
 | |
| 
 | |
| def flipwritable(fn, mode=None):
 | |
|     """
 | |
|     Flip the writability of a file and return the old mode. Returns None
 | |
|     if the file is already writable.
 | |
|     """
 | |
|     if os.access(fn, os.W_OK):
 | |
|         return None
 | |
|     old_mode = os.stat(fn).st_mode
 | |
|     os.chmod(fn, stat.S_IWRITE | old_mode)
 | |
|     return old_mode
 | |
| 
 | |
| def thin(path):
 | |
|     try:
 | |
|         subprocess.check_call(['lipo', path, '-verify_arch', 'ppc64'])
 | |
|         print '\tThinning', path
 | |
|     except:
 | |
|         return
 | |
|     else:
 | |
|         subprocess.check_call(['lipo', path, '-thin', 'x86_64', '-output', path])
 | |
| 
 | |
| STRIPCMD = ['/usr/bin/strip', '-x', '-S', '-']
 | |
| def strip_files(files, argv_max=(256 * 1024)):
 | |
|     """
 | |
|     Strip a list of files
 | |
|     """
 | |
|     tostrip = [(fn, flipwritable(fn)) for fn in files]
 | |
|     while tostrip:
 | |
|         cmd = list(STRIPCMD)
 | |
|         flips = []
 | |
|         pathlen = reduce(operator.add, [len(s) + 1 for s in cmd])
 | |
|         while pathlen < argv_max:
 | |
|             if not tostrip:
 | |
|                 break
 | |
|             added, flip = tostrip.pop()
 | |
|             pathlen += len(added) + 1
 | |
|             cmd.append(added)
 | |
|             flips.append((added, flip))
 | |
|         else:
 | |
|             cmd.pop()
 | |
|             tostrip.append(flips.pop())
 | |
|         os.spawnv(os.P_WAIT, cmd[0], cmd)
 | |
|         for args in flips:
 | |
|             flipwritable(*args)
 | |
| 
 | |
| def flush(func):
 | |
|     def ff(*args, **kwargs):
 | |
|         sys.stdout.flush()
 | |
|         sys.stderr.flush()
 | |
|         ret = func(*args, **kwargs)
 | |
|         sys.stdout.flush()
 | |
|         sys.stderr.flush()
 | |
|         return ret
 | |
|     return ff
 | |
| 
 | |
| class Py2App(object):
 | |
| 
 | |
|     FID = '@executable_path/../Frameworks'
 | |
| 
 | |
|     def __init__(self, build_dir):
 | |
|         self.build_dir = build_dir
 | |
|         self.contents_dir = join(self.build_dir, 'Contents')
 | |
|         self.resources_dir = join(self.contents_dir, 'Resources')
 | |
|         self.frameworks_dir = join(self.contents_dir, 'Frameworks')
 | |
|         self.version_info = '.'.join(map(str, sys.version_info[:2]))
 | |
|         self.to_strip = []
 | |
|         self.warnings = []
 | |
| 
 | |
|     def warn(self, *args):
 | |
|         self.warnings.append(args)
 | |
|         prefix = '' if args and args[0].startswith('WARNING:') else 'WARNING: '
 | |
|         sys.stdout.write(prefix+' '.join(args)+'\n')
 | |
|         sys.stdout.flush()
 | |
| 
 | |
| 
 | |
|     def run(self):
 | |
|         self.create_skeleton()
 | |
|         self.create_plist()
 | |
| 
 | |
|         self.add_python_framework()
 | |
|         self.add_qt_frameworks()
 | |
|         self.add_calibre_plugins()
 | |
|         self.add_podofo()
 | |
|         self.add_poppler()
 | |
|         self.add_libjpeg()
 | |
|         self.add_libpng()
 | |
|         self.add_fontconfig()
 | |
|         self.add_imagemagick()
 | |
|         self.add_misc_libraries()
 | |
| 
 | |
|         self.add_site_packages()
 | |
|         self.add_stdlib()
 | |
|         self.compile_py_modules()
 | |
| 
 | |
|         self.create_console_app()
 | |
| 
 | |
|         self.copy_launcher_and_site()
 | |
|         self.create_exe()
 | |
|         self.thin_to_x86_64()
 | |
|         self.strip_files()
 | |
| 
 | |
|         ret = self.makedmg(self.build_dir, APPNAME+'-'+VERSION+'-x86_64')
 | |
|         sys.stdout.flush()
 | |
|         sys.stderr.flush()
 | |
| 
 | |
|         print '\nThere were', len(self.warnings), 'warnings'
 | |
|         for w in list(self.warnings):
 | |
|             print
 | |
|             self.warn(*w)
 | |
|         return ret
 | |
| 
 | |
|     @flush
 | |
|     def thin_to_x86_64(self):
 | |
|         print '\nThinning to x86_64'
 | |
|         for y in (self.frameworks_dir, join(self.resources_dir, 'Python')):
 | |
|             for x in os.walk(y):
 | |
|                 for f in x[-1]:
 | |
|                     f = join(x[0], f)
 | |
|                     if not os.path.isfile(f): continue
 | |
|                     for t in ('.so', '.dylib', '/Python'):
 | |
|                         if f.endswith(t):
 | |
|                             thin(f)
 | |
|                             break
 | |
| 
 | |
|     @flush
 | |
|     def strip_files(self):
 | |
|         print '\nStripping files...'
 | |
|         strip_files(self.to_strip)
 | |
| 
 | |
|     @flush
 | |
|     def create_exe(self):
 | |
|         print '\nCreating launchers'
 | |
|         programs = {}
 | |
|         for program, module in zip(basenames['console'],
 | |
|                 main_modules['console'])+zip(basenames['gui'],
 | |
|                 main_modules['gui']):
 | |
|             programs[program] = module
 | |
|         programs = compile_launchers(self.contents_dir, programs)
 | |
|         for out in programs:
 | |
|             self.fix_dependencies_in_lib(out)
 | |
|         for module in main_modules['console'] + main_modules['gui']:
 | |
|             base = join(*module.split('.'))+'.py'
 | |
|             shutil.copy2(join('src', base),
 | |
|                     join(self.resources_dir, 'Python', 'site-packages', base))
 | |
| 
 | |
|     @flush
 | |
|     def set_id(self, path_to_lib, new_id):
 | |
|         old_mode = flipwritable(path_to_lib)
 | |
|         subprocess.check_call(['install_name_tool', '-id', new_id, path_to_lib])
 | |
|         if old_mode is not None:
 | |
|             flipwritable(path_to_lib, old_mode)
 | |
| 
 | |
|     @flush
 | |
|     def get_dependencies(self, path_to_lib):
 | |
|         raw = subprocess.Popen(['otool', '-L', path_to_lib],
 | |
|                 stdout=subprocess.PIPE).stdout.read()
 | |
|         for line in raw.splitlines():
 | |
|             if 'compatibility' not in line or line.strip().endswith(':'):
 | |
|                 continue
 | |
|             idx = line.find('(')
 | |
|             path = line[:idx].strip()
 | |
|             yield path
 | |
| 
 | |
|     @flush
 | |
|     def get_local_dependencies(self, path_to_lib):
 | |
|         for x in self.get_dependencies(path_to_lib):
 | |
|             for y in (SW+'/lib/', '/usr/local/lib/', SW+'/qt/lib/',
 | |
|                     SW+'/python/'):
 | |
|                 if x.startswith(y):
 | |
|                     yield x, x[len(y):]
 | |
|                     break
 | |
| 
 | |
|     @flush
 | |
|     def change_dep(self, old_dep, new_dep, path_to_lib):
 | |
|         print '\tResolving dependency %s to'%old_dep, new_dep
 | |
|         subprocess.check_call(['install_name_tool', '-change', old_dep, new_dep,
 | |
|             path_to_lib])
 | |
| 
 | |
|     @flush
 | |
|     def fix_dependencies_in_lib(self, path_to_lib):
 | |
|         print '\nFixing dependencies in', path_to_lib
 | |
|         self.to_strip.append(path_to_lib)
 | |
|         old_mode = flipwritable(path_to_lib)
 | |
|         for dep, bname in self.get_local_dependencies(path_to_lib):
 | |
|             ndep = self.FID+'/'+bname
 | |
|             self.change_dep(dep, ndep, path_to_lib)
 | |
|         if list(self.get_local_dependencies(path_to_lib)):
 | |
|             raise Exception('Failed to resolve deps in: '+path_to_lib)
 | |
|         if old_mode is not None:
 | |
|             flipwritable(path_to_lib, old_mode)
 | |
| 
 | |
|     @flush
 | |
|     def add_python_framework(self):
 | |
|         print '\nAdding Python framework'
 | |
|         src = join(SW, 'python', 'Python.framework')
 | |
|         x = join(self.frameworks_dir, 'Python.framework')
 | |
|         curr = os.path.realpath(join(src, 'Versions', 'Current'))
 | |
|         currd = join(x, 'Versions', basename(curr))
 | |
|         rd = join(currd, 'Resources')
 | |
|         os.makedirs(rd)
 | |
|         shutil.copy2(join(curr, 'Resources', 'Info.plist'), rd)
 | |
|         shutil.copy2(join(curr, 'Python'), currd)
 | |
|         self.set_id(join(currd, 'Python'),
 | |
|             self.FID+'/Python.framework/Versions/%s/Python'%basename(curr))
 | |
| 
 | |
|     @flush
 | |
|     def add_qt_frameworks(self):
 | |
|         for f in ('QtCore', 'QtGui', 'QtXml', 'QtNetwork', 'QtSvg', 'QtWebkit',
 | |
|                 'phonon'):
 | |
|             self.add_qt_framework(f)
 | |
|         for d in glob.glob(join(SW, 'qt', 'plugins', '*')):
 | |
|             shutil.copytree(d, join(self.contents_dir, 'MacOS', basename(d)))
 | |
|         for l in glob.glob(join(self.contents_dir, 'MacOS', '*/*.dylib')):
 | |
|             self.fix_dependencies_in_lib(l)
 | |
|             x = os.path.relpath(l, join(self.contents_dir, 'MacOS'))
 | |
|             self.set_id(l, '@executable_path/'+x)
 | |
| 
 | |
|     @flush
 | |
|     def add_qt_framework(self, f):
 | |
|         libname = f
 | |
|         f = f+'.framework'
 | |
|         src = join(SW, 'qt', 'lib', f)
 | |
|         ignore = shutil.ignore_patterns('Headers', '*.h', 'Headers/*')
 | |
|         dest = join(self.frameworks_dir, f)
 | |
|         shutil.copytree(src, dest, symlinks=True,
 | |
|                 ignore=ignore)
 | |
|         lib = os.path.realpath(join(dest, libname))
 | |
|         rpath = os.path.relpath(lib, self.frameworks_dir)
 | |
|         self.set_id(lib, self.FID+'/'+rpath)
 | |
|         self.fix_dependencies_in_lib(lib)
 | |
| 
 | |
|     @flush
 | |
|     def create_skeleton(self):
 | |
|         c = join(self.build_dir, 'Contents')
 | |
|         for x in ('Frameworks', 'MacOS', 'Resources'):
 | |
|             os.makedirs(join(c, x))
 | |
|         x = 'library.icns'
 | |
|         shutil.copyfile(join('icons', x), join(self.resources_dir, x))
 | |
| 
 | |
|     @flush
 | |
|     def add_calibre_plugins(self):
 | |
|         dest = join(self.frameworks_dir, 'plugins')
 | |
|         os.mkdir(dest)
 | |
|         for f in glob.glob('src/calibre/plugins/*.so'):
 | |
|             shutil.copy2(f, dest)
 | |
|             self.fix_dependencies_in_lib(join(dest, basename(f)))
 | |
|             if 'podofo' in f:
 | |
|                 self.change_dep('libpodofo.0.6.99.dylib',
 | |
|                 self.FID+'/'+'libpodofo.0.6.99.dylib', join(dest, basename(f)))
 | |
| 
 | |
| 
 | |
|     @flush
 | |
|     def create_plist(self):
 | |
|         env = dict(**ENV)
 | |
|         env['CALIBRE_LAUNCHED_FROM_BUNDLE']='1';
 | |
| 
 | |
|         pl = dict(
 | |
|                 CFBundleDevelopmentRegion='English',
 | |
|                 CFBundleDisplayName=APPNAME,
 | |
|                 CFBundleName=APPNAME,
 | |
|                 CFBundleIdentifier='net.kovidgoyal.calibre',
 | |
|                 CFBundleVersion=VERSION,
 | |
|                 CFBundlePackageType='APPL',
 | |
|                 CFBundleSignature='????',
 | |
|                 CFBundleExecutable='calibre',
 | |
|                 LSMinimumSystemVersion='10.5.2',
 | |
|                 LSRequiresNativeExecution=True,
 | |
|                 NSAppleScriptEnabled=False,
 | |
|                 NSHumanReadableCopyright='Copyright 2008, Kovid Goyal',
 | |
|                 CFBundleGetInfoString=('calibre, an E-book management '
 | |
|                 'application. Visit http://calibre.kovidgoyal.net for details.'),
 | |
|                 CFBundleIconFile='library.icns',
 | |
|                 LSMultipleInstancesProhibited=True,
 | |
|                 LSEnvironment=env
 | |
|         )
 | |
|         plistlib.writePlist(pl, join(self.contents_dir, 'Info.plist'))
 | |
| 
 | |
|     @flush
 | |
|     def install_dylib(self, path, set_id=True):
 | |
|         shutil.copy2(path, self.frameworks_dir)
 | |
|         if set_id:
 | |
|             self.set_id(join(self.frameworks_dir, basename(path)),
 | |
|                     self.FID+'/'+basename(path))
 | |
|         self.fix_dependencies_in_lib(join(self.frameworks_dir, basename(path)))
 | |
| 
 | |
|     @flush
 | |
|     def add_podofo(self):
 | |
|         print '\nAdding PoDoFo'
 | |
|         pdf = join(SW, 'lib', 'libpodofo.0.6.99.dylib')
 | |
|         self.install_dylib(pdf)
 | |
| 
 | |
|     @flush
 | |
|     def add_poppler(self):
 | |
|         print '\nAdding poppler'
 | |
|         for x in ('libpoppler.4.dylib', 'libpoppler-qt4.3.dylib'):
 | |
|             self.install_dylib(os.path.join(SW, 'lib', x))
 | |
|         self.install_dylib(os.path.join(SW, 'bin', 'pdftohtml'), False)
 | |
| 
 | |
|     @flush
 | |
|     def add_libjpeg(self):
 | |
|         print '\nAdding libjpeg'
 | |
|         self.install_dylib(os.path.join(SW, 'lib', 'libjpeg.7.dylib'))
 | |
| 
 | |
|     @flush
 | |
|     def add_libpng(self):
 | |
|         print '\nAdding libpng'
 | |
|         self.install_dylib(os.path.join(SW, 'lib', 'libpng12.0.dylib'))
 | |
| 
 | |
|     @flush
 | |
|     def add_fontconfig(self):
 | |
|         print '\nAdding fontconfig'
 | |
|         for x in ('fontconfig.1', 'freetype.6', 'expat.1'):
 | |
|             src = os.path.join(SW, 'lib', 'lib'+x+'.dylib')
 | |
|             self.install_dylib(src)
 | |
|         dst = os.path.join(self.resources_dir, 'fonts')
 | |
|         if os.path.exists(dst):
 | |
|             shutil.rmtree(dst)
 | |
|         src = os.path.join(SW, 'etc', 'fonts')
 | |
|         shutil.copytree(src, dst, symlinks=False)
 | |
|         fc = os.path.join(dst, 'fonts.conf')
 | |
|         raw = open(fc, 'rb').read()
 | |
|         raw = raw.replace('<dir>/usr/share/fonts</dir>', '''\
 | |
|         <dir>/Library/Fonts</dir>
 | |
|         <dir>/Network/Library/Fonts</dir>
 | |
|         <dir>/System/Library/Fonts</dir>
 | |
|         <dir>/usr/X11R6/lib/X11/fonts</dir>
 | |
|         <dir>/usr/share/fonts</dir>
 | |
|         <dir>/var/root/Library/Fonts</dir>
 | |
|         <dir>/usr/share/fonts</dir>
 | |
|         ''')
 | |
|         open(fc, 'wb').write(raw)
 | |
| 
 | |
|     @flush
 | |
|     def add_imagemagick(self):
 | |
|         print '\nAdding ImageMagick'
 | |
|         for x in ('Wand', 'Core'):
 | |
|             self.install_dylib(os.path.join(SW, 'lib', 'libMagick%s.2.dylib'%x))
 | |
|         idir = glob.glob(os.path.join(SW, 'lib', 'ImageMagick-*'))[-1]
 | |
|         dest = os.path.join(self.frameworks_dir, 'ImageMagick', 'lib')
 | |
|         if not os.path.exists(dest):
 | |
|             os.makedirs(dest)
 | |
|         dest = os.path.join(dest, os.path.basename(idir))
 | |
|         if os.path.exists(dest):
 | |
|             shutil.rmtree(dest)
 | |
|         shutil.copytree(idir, dest, True)
 | |
|         for x in os.walk(dest):
 | |
|             for f in x[-1]:
 | |
|                 if f.endswith('.so'):
 | |
|                     f = join(x[0], f)
 | |
|                     self.fix_dependencies_in_lib(f)
 | |
| 
 | |
|     @flush
 | |
|     def add_misc_libraries(self):
 | |
|         for x in ('usb', 'unrar', 'readline.6.0'):
 | |
|             print '\nAdding', x
 | |
|             x = 'lib%s.dylib'%x
 | |
|             shutil.copy2(join(SW, 'lib', x), self.frameworks_dir)
 | |
|             self.set_id(join(self.frameworks_dir, x), self.FID+'/'+x)
 | |
| 
 | |
|     @flush
 | |
|     def add_site_packages(self):
 | |
|         print '\nAdding site-packages'
 | |
|         self.site_packages = join(self.resources_dir, 'Python', 'site-packages')
 | |
|         os.makedirs(self.site_packages)
 | |
|         paths = reversed(map(abspath, [x for x in sys.path if x.startswith('/')]))
 | |
|         upaths = []
 | |
|         for x in paths:
 | |
|             if x.endswith('/PIL') or 'site-packages' not in x:
 | |
|                 continue
 | |
|             if x not in upaths:
 | |
|                 upaths.append(x)
 | |
|         upaths.append(os.path.expanduser('~/build/calibre/src'))
 | |
|         for x in upaths:
 | |
|             tdir = None
 | |
|             try:
 | |
|                 if not os.path.isdir(x):
 | |
|                     try:
 | |
|                         zf = zipfile.ZipFile(x)
 | |
|                     except:
 | |
|                         self.warn(x, 'is neither a directory nor a zipfile')
 | |
|                         continue
 | |
|                     tdir = tempfile.mkdtemp()
 | |
|                     zf.extractall(tdir)
 | |
|                     x = tdir
 | |
|                 self.add_modules_from_dir(x)
 | |
|                 self.add_packages_from_dir(x)
 | |
|             finally:
 | |
|                 if tdir is not None:
 | |
|                     shutil.rmtree(tdir)
 | |
|         self.remove_bytecode(join(self.resources_dir, 'Python', 'site-packages'))
 | |
| 
 | |
|     @flush
 | |
|     def add_modules_from_dir(self, src):
 | |
|         for x in glob.glob(join(src, '*.py'))+glob.glob(join(src, '*.so')):
 | |
|             dest = join(self.site_packages, basename(x))
 | |
|             shutil.copy2(x, self.site_packages)
 | |
|             if x.endswith('.so'):
 | |
|                 self.fix_dependencies_in_lib(x)
 | |
| 
 | |
|     @flush
 | |
|     def add_packages_from_dir(self, src):
 | |
|         for x in os.listdir(src):
 | |
|             x = join(src, x)
 | |
|             if os.path.isdir(x) and os.path.exists(join(x, '__init__.py')):
 | |
|                 if self.filter_package(basename(x)):
 | |
|                     continue
 | |
|                 self.add_package_dir(x)
 | |
| 
 | |
|     @flush
 | |
|     def add_package_dir(self, x, dest=None):
 | |
|         def ignore(root, files):
 | |
|             ans  = []
 | |
|             for y in files:
 | |
|                 ext = os.path.splitext(y)[1]
 | |
|                 if ext not in ('', '.py', '.so') or \
 | |
|                     (not ext and not os.path.isdir(join(root, y))):
 | |
|                         ans.append(y)
 | |
| 
 | |
|             return ans
 | |
|         if dest is None:
 | |
|             dest = self.site_packages
 | |
|         dest = join(dest, basename(x))
 | |
|         shutil.copytree(x, dest, symlinks=True, ignore=ignore)
 | |
|         self.postprocess_package(x, dest)
 | |
|         for x in os.walk(dest):
 | |
|             for f in x[-1]:
 | |
|                 if f.endswith('.so'):
 | |
|                     f = join(x[0], f)
 | |
|                     self.fix_dependencies_in_lib(f)
 | |
| 
 | |
|     @flush
 | |
|     def filter_package(self, name):
 | |
|         return name in ('Cython', 'modulegraph', 'macholib', 'py2app',
 | |
|         'bdist_mpkg', 'altgraph')
 | |
| 
 | |
|     @flush
 | |
|     def postprocess_package(self, src_path, dest_path):
 | |
|         pass
 | |
| 
 | |
|     @flush
 | |
|     def add_stdlib(self):
 | |
|         print '\nAdding python stdlib'
 | |
|         src = join(SW, 'python/Python.framework/Versions/Current/lib/python')
 | |
|         src += self.version_info
 | |
|         dest = join(self.resources_dir, 'Python', 'lib', 'python')
 | |
|         dest += self.version_info
 | |
|         os.makedirs(dest)
 | |
|         for x in os.listdir(src):
 | |
|             if x in ('site-packages', 'config', 'test', 'lib2to3', 'lib-tk',
 | |
|             'lib-old', 'idlelib', 'plat-mac', 'plat-darwin', 'site.py'):
 | |
|                 continue
 | |
|             x = join(src, x)
 | |
|             if os.path.isdir(x):
 | |
|                 self.add_package_dir(x, dest)
 | |
|             elif os.path.splitext(x)[1] in ('.so', '.py'):
 | |
|                 shutil.copy2(x, dest)
 | |
|                 dest2 = join(dest, basename(x))
 | |
|                 if dest2.endswith('.so'):
 | |
|                     self.fix_dependencies_in_lib(dest2)
 | |
|         self.remove_bytecode(join(self.resources_dir, 'Python', 'lib'))
 | |
| 
 | |
|     @flush
 | |
|     def remove_bytecode(self, dest):
 | |
|         for x in os.walk(dest):
 | |
|             root = x[0]
 | |
|             for f in x[-1]:
 | |
|                 if os.path.splitext(f) in ('.pyc', '.pyo'):
 | |
|                     os.remove(join(root, f))
 | |
| 
 | |
|     @flush
 | |
|     def compile_py_modules(self):
 | |
|         print '\nCompiling Python modules'
 | |
|         base = join(self.resources_dir, 'Python')
 | |
|         for x in os.walk(base):
 | |
|             root = x[0]
 | |
|             for f in x[-1]:
 | |
|                 if f.endswith('.py'):
 | |
|                     y = join(root, f)
 | |
|                     rel = os.path.relpath(y, base)
 | |
|                     try:
 | |
|                         py_compile.compile(y, dfile=rel, doraise=True)
 | |
|                         os.remove(y)
 | |
|                     except:
 | |
|                         self.warn('WARNING: Failed to byte-compile', y)
 | |
| 
 | |
|     @flush
 | |
|     def create_console_app(self):
 | |
|         print '\nCreating console.app'
 | |
|         cc_dir = os.path.join(self.contents_dir, 'console.app', 'Contents')
 | |
|         os.makedirs(cc_dir)
 | |
|         for x in os.listdir(self.contents_dir):
 | |
|             if x == 'console.app':
 | |
|                 continue
 | |
|             if x == 'Info.plist':
 | |
|                 plist = plistlib.readPlist(join(self.contents_dir, x))
 | |
|                 plist['LSUIElement'] = '1'
 | |
|                 plistlib.writePlist(plist, join(cc_dir, x))
 | |
|             else:
 | |
|                 os.symlink(join('../..', x),
 | |
|                            join(cc_dir, x))
 | |
| 
 | |
|     @flush
 | |
|     def copy_launcher_and_site(self):
 | |
|         base = os.path.dirname(__file__)
 | |
|         shutil.copy2(join(base, 'launcher.py'), self.resources_dir)
 | |
|         shutil.copy2(join(base, 'site.py'), join(self.resources_dir, 'Python',
 | |
|             'lib', 'python'+self.version_info))
 | |
| 
 | |
| 
 | |
|     @flush
 | |
|     def makedmg(self, d, volname,
 | |
|                 destdir='dist',
 | |
|                 internet_enable=True,
 | |
|                 format='UDBZ'):
 | |
|         ''' Copy a directory d into a dmg named volname '''
 | |
|         print '\nCreating dmg'
 | |
|         sys.stdout.flush()
 | |
|         if not os.path.exists(destdir):
 | |
|             os.makedirs(destdir)
 | |
|         dmg = os.path.join(destdir, volname+'.dmg')
 | |
|         if os.path.exists(dmg):
 | |
|             os.unlink(dmg)
 | |
|         subprocess.check_call(['/usr/bin/hdiutil', 'create', '-srcfolder', os.path.abspath(d),
 | |
|                                '-volname', volname, '-format', format, dmg])
 | |
|         if internet_enable:
 | |
|            subprocess.check_call(['/usr/bin/hdiutil', 'internet-enable', '-yes', dmg])
 | |
|         size = os.stat(dmg).st_size/(1024*1024.)
 | |
|         print '\nInstaller size: %.2fMB\n'%size
 | |
|         return dmg
 | |
| 
 | |
| def test_exe():
 | |
|     build_dir = abspath(join('build', APPNAME+'.app'))
 | |
|     py2app = Py2App(build_dir)
 | |
|     py2app.create_exe()
 | |
|     return 0
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     if 'test_exe' in sys.argv:
 | |
|         return test_exe()
 | |
|     build_dir = abspath(join('build', APPNAME+'.app'))
 | |
|     if os.path.exists(build_dir):
 | |
|         shutil.rmtree(build_dir)
 | |
|     os.makedirs(build_dir)
 | |
|     py2app = Py2App(build_dir)
 | |
|     py2app.run()
 | |
|     return 0
 | |
| 
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     sys.exit(main())
 |