File: pymailgui-products/unzipped/build/build-app-exe/macosx/unused-defunct/build-large-147Mzip-200Mlive.py

#!/usr/bin/env python3
"""
=============================================================================
Make a Mac OS X App bundle (folder), using py2app.
Based on the more-complicated build.py of PyEdit.
Main file: run me in this folder to build the app.

An app allows text files to be associated to auto-open in PyEdit on clicks;
makes the program immune from Python changes; requires no Python installs;
and better supports file drag-and-drops, program icons, and more (but also
does a woefully-good job of hiding user-config source files and auto-saves!).

Mac app also required... a mac-format .icns icon (the latter became an 
iconify.py extension), and fixfrozenpaths.py's context configurations.

Besides the executable, the app needs:
-MailConfigs: its files must be source code, and user-visible and editable;
-icon for the exe/app (window borders/app bar for Windows/Linux);
-UserGuide.html and docetc items it uses at runtime;
 
py2app sets the cwd to the bundle's Contents/Resource folder in all cases:
add '.' to sys.path, and use files copied to .=Resources, to which __file__
will refer.  Associations are irrelevant and unused here.

NOTE: it's assumed that the frozen app, plus the Python and Tk included 
in the app bundle are univeral binaries, supporting both 64- and 32-bit
machines.  This appears to be so, though the app's portability to older 
OS X versions remains to be shown (10.11 El Capitan is build host).
=============================================================================
"""

import os, sys, shutil
join, sep = os.path.join, os.path.sep
force = len(sys.argv) > 1                 # remake icon if any arg
startdir = os.getcwd()                    # this build script's dir

# 'python3' fails in both IDLE and PyEdit RunCode (env's PATH not inherited?)
python = '/usr/local/bin/python3'  # sys.executable (else proxy in PyEdit?)

#----------------------------------------------------------------------------
# make app's icon if one doesn't already exist
#----------------------------------------------------------------------------

iconship = join('..', '..', '..', 'icons')
iconmake = join('..', '..', 'build-icons')
iconname = 'pymailgui'
iconfile = iconname + '.icns'

# step into icon build dir and make
if force or not os.path.exists(iconship + sep + iconfile):
    os.chdir(iconmake)
   #os.system('iconutil -c icns %s.iconset' % iconname)                    # Apple util
   #os.system('./resize-on-mac.sh Pyedit1024new images-pyedit')            # just once
    os.system('%s iconify.py -mac images-pyedit %s' % (python, iconname))  # iconify 2.0
    os.chdir(startdir)
    shutil.move(join(iconmake, iconfile), join(iconship, iconfile))     # mv to ship

#----------------------------------------------------------------------------
# first, copy source tree to temp folder to avoid accidental code loss;
# [update - setup and teardown steps are now automated (run this script in 
# its dir), and Info.plist edits are now automatic by setup.py options;]
#----------------------------------------------------------------------------

# automated setup - run in this file's dir
temp = '/Users/blue/Desktop/tempsrc'                    # cp can't include self!
if os.path.exists(temp):
    shutil.rmtree(temp)
os.mkdir(temp)

# move all to temp (no PP4E+TextEditor moves needed)
shutil.copytree('../../../../pymailgui', temp+'/pymailgui', symlinks=True) 
shutil.copy('setup.py', temp+'/pymailgui')              # add setup script to root
os.chdir(temp+'/pymailgui')                             # goto temp build dir

#----------------------------------------------------------------------------
# Drop big and irrelevant folders, plus any personal email stuff
#----------------------------------------------------------------------------

# 1) strip the 400M+ nested PyEdit build dirs
pyeditbuild = 'PyMailGui-PP4E/PP4E/Gui/TextEditor/build'
shutil.rmtree(pyeditbuild)
os.mkdir(pyeditbuild)
dummy = open(join(pyeditbuild, 'README.txt'), 'w')
dummy.write('Content removed: see PyEdit for its build scripts.\n')
dummy.close()  # else in-use on rmtree non Win (Mac?)

# 2) pyedit auto-saves; pass on reinstating zipped examples in docetc/examples
autosave_pmg = 'PyMailGui-PP4E/__pyedit-autosaves__'
autosave_pe  = 'PyMailGui-PP4E/PP4E/Gui/TextEditor/__pyedit-autosaves__'

for asave in (autosave_pmg, autosave_pe):
    for item in os.listdir(asave):
        if item != 'README-autosaves.txt':
            itempath = join(asave, item)
            print('Removing', itempath)
            os.remove(itempath)

# 3) TempParts; pass on reinstating zipped example in docetc/examples
tempparts = 'PyMailGui-PP4E/TempParts'
for item in os.listdir(tempparts):
    if item not in ['README-TempParts.txt', 'DSC00565.JPG', 'DSC03890.JPG']:
        itempath = join(tempparts, item)
        print('Removing', itempath)
        os.remove(itempath)       

# 4) sent mail; very dangerous...
print('Replacing sentmail')
sentmail = 'PyMailGui-PP4E/sentmail.txt'
os.remove(sentmail)
os.rename('PyMailGui-PP4E/sentmail-save.txt', sentmail)

#----------------------------------------------------------------------------
# cp so use name for both the app-bundle folder and auto-menu title;
# this name must also be used in this project's setup.py file here;
# we can't rename these after the build, and the launcher is ingrained;
#----------------------------------------------------------------------------

# shutil.copy('textEditor.py', 'PyEdit.py')
# not here: rename after launcher app built ahead

#----------------------------------------------------------------------------
# build app-bundle folder in ./dist, using ./setup.py, copying N extras
# to the main Resources folder along with the generated program itself;
# this uses --resources to copy non-code extras, and -extras-scripts to
# also freeze related scripts shipped with mergeall, so that they can
# be run from the app's Content/MacOS folder without a ".py" extension 
# and without requiring a separate Python install.
#
# Update: --extras-scripts is unused here, as there are no other scripts.
# Instead, we use --package to bundle everything needed for the main
# PyMailGui program into the app's Python executable used to run the
# launcher.  This way, the launcher can spawn PyMailGui as source code
# (included in Content/Resources manually) using the app's bundled Python.
# That is, all PyMailGui.py requirements are "baked in" to the app's Python
# used by the frozen launcher executable.  Running PyMailGUI as source also
# allows its subfolder structure to remain intact, which is important for
# the MailConfigs top-level folder scheme.
#
# Most other source is for its docs only -- it may not run as source.
# Exception: the embedded PyEdit code can be run standalone in this app
# with a locally-installed Python, because it's included in full source
# form (but get the PyEdit app for a better user experience).
#----------------------------------------------------------------------------

extras = [                          # tbd: use a 'tools' folder?
    'MailConfigs',                  # ship these in Content/Resources='.'
    'README.txt', 
    'icons',
    'docetc',
    'UserGuide.html',
    'PyMailGui-PP4E',
    'Launch_PyEdit.pyw'             # runs as source if full PyMailGUI pkg included
]

alsofreeze = [                      # bake-in other scripts' requirements
    #'PyMailGui-PP4E/PyMailGui.py'  # not required: full --package bundled
]

exitstat = os.system(
    '%s setup.py py2app' 
    '   --iconfile icons/pymailgui.icns'
    '   --resources %s'
    '   --package PyMailGui-PP4E'
    % (python, ','.join(extras))
)

if exitstat:
    print('ERROR: build failed:', exitstat)
    sys.exit(exitstat)   # don't continue here

#----------------------------------------------------------------------------
# cleanup: move and zip the app folder for easy xfer and backup (it has
# _very_ many files: nearly 3K files+folders for the current PyEdit App);
# [update - teardown actions are now automated (but still no data to copy)]
# don't copy extras to Contents/Resources folder here: automatic via the 
# py2app args above;  fixfrozenpaths.py arranges to see these as needed;
# DON'T -skipcruft in the zip command: py2app makes a Resources/site.pyc!
#----------------------------------------------------------------------------

# zip command: use portable ziptools (vs: 'zip -r %s %s' % (thezip, thedir))
thedir = 'PyMailGUI.app'
thezip = thedir + '.zip'
code   = '/MY-STUFF/Code/ziptools/link'
zipit  = '%s %s/zip-create.py ../%s %s' % (python, code, thezip, thedir)

# move dist product folder here
os.chdir(startdir)
if os.path.exists('dist'):
    shutil.rmtree('dist')                      # nuke bogus retained temp?
shutil.move(temp+'/pymailgui/dist', '.')
shutil.rmtree(temp)                            # rm temp build tree 

# zip the nested app folder - unzip to test and use here or elsewhere
if os.path.exists(thezip):
    shutil.move(thezip, 'prev-'+thezip)        # save previous version
if os.path.exists(thedir):
    shutil.rmtree(thedir)                      # nuke unzipped version

os.chdir('dist')   
shutil.move('Launch_PyMailGUI.app', thedir)

os.system(zipit)                               # run zip in dist: has app dir
os.chdir('..')   
shutil.rmtree('dist')                          # rm dist: _very_ many files

print('Done: see ./%s' % thezip)

# +unzip app and copy it to /Applications to make it official



[Home page] Books Code Blog Python Author Train Find ©M.Lutz