File: pyedit-products/unzipped/build/build-app-exe/linux/build.py

#!/usr/bin/env python3
"""
===========================================================================
Main file: make a Linux single-file executable with PyInstaller,
and manually copy some data items to its folder.

There is no setup.py file for PyIstaller.
Python recoding of an original shell-script version. 

Associating files with executables on Linux can be tedious (e.g., editing
/usr/share mime-list and .desktop files).  See the web for resources:
https://duckduckgo.com/?q=associate+program+with+file+ubuntu

See also the ../windows/build.py PyInstaller build for Windows; because
it's so similar to this, most comments have been stripped here for space.

ODDMENT: to get the PyInstaller build to work on Linux, had to make a
dummy, empty /usr/include/Python3.5m/pyconfig.h file.  It may have also
worked to install "python_dev" instead (unknown).  The pyconfig.h file
is apparently required for some stdlib module, most likely distutils,
and perhaps for its PyInstalller hook file.  The consequences of stubbing
it out remain unknown (but the frozen PyEdit runs fine).
===========================================================================
"""

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

# this is curently moot on Linux 
# bitsize = 64  # or 32
# mainhost = (bitsize == 64)
mainhost = True

#----------------------------------------------------------------------------
# force all stdlib mods to be baked-in to proxy exe's python, for Run Code
#----------------------------------------------------------------------------

if mainhost:
    # make hook file
    exitstat = os.system('"%s" include-full-stdlib.py' % python)
    assert exitstat == 0

#----------------------------------------------------------------------------
# make exe's icon if doesn't exist (NOT for Linux - uses image for app bar)
#----------------------------------------------------------------------------

pass

#----------------------------------------------------------------------------
# first: copy PP4E, move its TextEditor to root, and nest PP4E inside it;
# [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 = '/home/name/Desktop/tempsrc'                    # cp can't include self!
if os.path.exists(temp):
    shutil.rmtree(temp)
os.mkdir(temp)

# move all to temp, nest PP4E in TextEditor
shutil.copytree('../../../../../../PP4E', temp+'/PP4E', symlinks=True) 
shutil.move(temp+'/PP4E/Gui/TextEditor', temp)         # move nested up to temp root
shutil.move(temp+'/PP4E', temp+'/TextEditor')          # move PP4E down to nested
#shutil.copy('setup.py', temp+'/TextEditor')           # not for pyinstaller
os.chdir(temp+'/TextEditor')                           # goto temp build dir

#--------------------------------------------------------------------------
# build one-file exe in ./dist (now actually _two_ exes, per below)
# ABOUT THE EXTRA EXECUTABLE and Issues Summary: see ../windows/build.py
# NOTE: the icon option is ignored on Linux (but PyEdit sets in app bar).
#--------------------------------------------------------------------------

# may not be on PATH
pyscripts = ''  # with trailing / if used

exitstat = os.system(
    '%spyinstaller'
    '   --onefile'
    '   --windowed'
    '   --icon icons/pyedit-window-main.gif'   # icon ignored in Linux
    '   --exclude-module textConfig'
    '   textEditor.py' % pyscripts)            # can't list subprocproxy.py too

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

exitstat = os.system(
    '%spyinstaller'
    '   --onefile'
    '   --noconsole'
    '   --icon icons/pyedit-subprocproxy.gif'
    '   --exclude-module textConfig'
    '   --additional-hooks-dir build/build-app-exe/linux'
    '   subprocproxy.py' % pyscripts)

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

#--------------------------------------------------------------------------
# use exe (not script) name
#--------------------------------------------------------------------------

shutil.move('dist/textEditor', 'dist/PyEdit')

#--------------------------------------------------------------------------
# copy extras to exe's folder: textEditor.py arranges to see these;
# not --add-data: it gets unzipped in a Temp dir the user won't see...
#--------------------------------------------------------------------------

extras = ['textConfig.py', 
          'README.txt', 
          'icons',
          'tools',
          'docetc', 
          'UserGuide.html',
          'subprocproxy.py']       # proxy: ship frozen AND source versions

for name in extras:
    if os.path.isfile(name):
         shutil.copy(name, 'dist')
    else:
         shutil.copytree(name, join('dist', name))

#----------------------------------------------------------------------------
# cleanup: move and zip the exe folder for easy xfer (just a few files here);
# [update - teardown actions are now automated (but still no data to copy)]
#----------------------------------------------------------------------------

# zip command: use portable ziptools
thedir = 'PyEdit'             # + ('-64bit' if bitsize == 64 else '-32bit')
thezip = thedir + '.zip'
code   = '/media/name/End_of_the_drive/MARKS-STUFF/Code/mergeall/test/ziptools'
zipit  = '%s %s/zip-create.py %s %s -skipcruft' % (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+'/TextEditor/dist', '.')
shutil.rmtree(temp)                                # rm temp build tree 

# zip the exe=dist 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.rename('dist', thedir)                          # rename for unzip name
os.system(zipit) 
shutil.rmtree(thedir)                              # no need to save raw dist

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

# +unzip exe folder, and move to $HOME or desktop (?) to make it permanent



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