Skip to content

Commit

Permalink
Patched assorted (minor) glitches for macOS. Improvements for cross p…
Browse files Browse the repository at this point in the history
…latform logic regarding binary and icon names, along with launching macOS .app (gui binaries).
  • Loading branch information
BuvinJ committed Jan 20, 2019
1 parent 6670344 commit 3eeefd9
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 68 deletions.
1 change: 1 addition & 0 deletions distbuilder/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
, splitExt \
, run \
, runPy \
, normBinaryName \
, toZipFile \
, moveToDesktop \
, moveToHomeDir \
Expand Down
9 changes: 6 additions & 3 deletions distbuilder/master.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ def qtIfwConfig( self, pyInstConfig=None ):
def qtIfwConfigXml( self ) :
return QtIfwConfigXml( self.productName, self.binaryName,
self.__versionStr(), self.companyLegalName,
self.companyTradeName, self.iconFilePath )
iconFilePath=self.iconFilePath,
isGui=self.isGui,
companyTradeName=self.companyTradeName )

def qtIfwPackageXml( self ) :
return QtIfwPackageXml( self.__ifwPkgName(), self.productName, self.description,
Expand All @@ -96,9 +98,10 @@ def qtIfwPackageXml( self ) :
def qtIfwPackageScript( self, pyInstConfig=None ) :
script = QtIfwPackageScript( self.__ifwPkgName(),
fileName=self.ifwScriptName,
exeName=self.binaryName,
exeName=self.binaryName,
isGui=self.isGui,
script=self.ifwScriptPath,
srcPath=self.ifwScriptPath )
scriptPath=self.ifwScriptPath )
if IS_LINUX:
script.exeVersion = self.__versionStr()
if pyInstConfig is not None:
Expand Down
62 changes: 42 additions & 20 deletions distbuilder/py_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
from distbuilder.util import * # @UnusedWildImport
from distbuilder.opy_library import obfuscatePy, OBFUS_DIR_PATH

PYINST_BIN_NAME = util._normExeName( "pyinstaller" )
PYINST_BIN_NAME = util.normBinaryName( "pyinstaller" )

SPEC_EXT = ".spec"

BUILD_DIR_PATH = absPath( "build" )
DIST_DIR_PATH = absPath( "dist" )
CACHE_DIR_PATH = absPath( "__pycache__" )

__TEMP_NEST_DIR_NAME = "__nested__"

# -----------------------------------------------------------------------------
class PyInstallerConfig:
"""
Expand Down Expand Up @@ -98,9 +100,11 @@ def toPyInstallerSrcDestSpec( pyInstArg, paths ):
if IS_LINUX :
# icon emmbedding is not supported by PyInstaller for Linux,
# this is handled by the library wrapper independently
self._pngIconResPath = splitExt( self.iconFilePath )[0] +".png"
self._pngIconResPath = util._normIconName(
self.iconFilePath, isPathPreserved=True )
self.iconFilePath = None
elif( isinstance( self.iconFilePath, tuple ) or
elif( IS_WINDOWS and
isinstance( self.iconFilePath, tuple ) or
isinstance( self.iconFilePath, list ) ):
# if the iconFilePath is a tuple or list,
# it represents a windows exe path and an
Expand All @@ -110,9 +114,8 @@ def toPyInstallerSrcDestSpec( pyInstArg, paths ):
self.iconFilePath[0], self.iconFilePath[1] )
else : raise
else :
# auto convert between Windows and Mac icon extensions
self.iconFilePath = ( splitExt( self.iconFilePath )[0] +
(".icns" if IS_MACOS else ".ico") )
self.iconFilePath = util._normIconName(
self.iconFilePath, isPathPreserved=True )
except: self.iconFilePath = None
iconSpec = ( '--icon "%s"' % (self.iconFilePath,)
if self.iconFilePath else "" )
Expand Down Expand Up @@ -252,9 +255,34 @@ def buildExecutable( name=None, entryPointPy=None,

# Build the executable using PyInstaller
__runPyInstaller( pyInstConfig )

# Discard all temp files (but not distDir!)
__clean( pyInstConfig )
__clean( pyInstConfig )

# eliminate the directory nesting created when the
# binary is not bundled into one file
if not pyInstConfig.isOneFile :
print( '"UN-nesting" the dist directory content...' )
nestedInitDir = joinPath( distDirPath, name )
nestedTempDir = joinPath( distDirPath, __TEMP_NEST_DIR_NAME )
if isDir( nestedInitDir ):
rename( nestedInitDir, nestedTempDir )
dirEntries = listdir(nestedTempDir)
for entry in dirEntries :
move( joinPath( nestedTempDir, entry ),
joinPath( distDirPath, entry ) )
removeDir( nestedTempDir )

# Confirm success
exePath = joinPath( distDirPath, util.normBinaryName( name ) )
if IS_MACOS and pyInstConfig.isGui :
# Remove extraneous UNIX binary, and point result to the .app file
if isFile( exePath ) : removeFile( exePath )
exePath = normBinaryName( exePath, isPathPreserved=True, isGui=True )
if not exists(exePath) :
raise Exception( 'FAILED to create "%s"' % (exePath,) )
print( 'Binary built successfully!\n"%s"' % (exePath,) )
print('')

# On Linux, automatically add a png icon to the
# external resources, if one exists and is not already included
Expand All @@ -269,15 +297,7 @@ def buildExecutable( name=None, entryPointPy=None,
if isRes: break
if not isRes: distResources.append( pngPath )
except: pass

# Confirm success
exePath = joinPath( distDirPath, util._normExeName( name ) )
if not exists(exePath) :
print( 'Binary not found: "%s"' % (exePath,) )
raise Exception( "Binary building failure!" )
print( 'Binary built successfully!\n"%s"' % (exePath,) )
print('')


# Add additional distribution resources
for res in distResources:
src, dest = util._toSrcDestPair( res, destDir=distDirPath )
Expand All @@ -303,10 +323,10 @@ def buildExecutable( name=None, entryPointPy=None,
return distDirPath, exePath

# -----------------------------------------------------------------------------
def __runPyInstaller( config ) :
def __runPyInstaller( pyInstConfig ) :
util._system( '%s %s "%s"' %
( config.pyInstallerPath, str(config),
normpath(config.entryPointPy) ) )
( pyInstConfig.pyInstallerPath, str(pyInstConfig),
normpath(pyInstConfig.entryPointPy) ) )

def __clean( pyInstConfig, distDirPath=None ) :
if distDirPath and exists( distDirPath ) :
Expand All @@ -321,3 +341,5 @@ def __clean( pyInstConfig, distDirPath=None ) :
pyInstConfig.versionFilePath is not None and
isFile( pyInstConfig.versionFilePath ) ) :
removeFile( pyInstConfig.versionFilePath )


66 changes: 41 additions & 25 deletions distbuilder/qt_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,16 @@

BUILD_SETUP_DIR_PATH = absPath( "build_setup" )
INSTALLER_DIR_PATH = "installer"
DEFAULT_SETUP_NAME = util._normExeName( "setup" )
DEFAULT_SETUP_NAME = util.normBinaryName( "setup" )
DEFAULT_QT_IFW_SCRIPT_NAME = "installscript.qs"

QT_IFW_VERBOSE_SWITCH = '-v'

QT_IFW_DIR_ENV_VAR = "QT_IFW_DIR"
QT_BIN_DIR_ENV_VAR = "QT_BIN_DIR"

__MACOS_SETUP_EXT = ".app"

__BIN_SUB_DIR = "bin"
__QT_INSTALL_CREATOR_EXE_NAME = util._normExeName( "binarycreator" )
__QT_INSTALL_CREATOR_EXE_NAME = util.normBinaryName( "binarycreator" )

__QT_WINDOWS_DEPLOY_EXE_NAME = "windeployqt.exe"
__QT_WINDOWS_DEPLOY_QML_SWITCH = "--qmldir"
Expand Down Expand Up @@ -67,7 +65,7 @@ def __init__( self,
# IFW tool path (attempt to use environmental variable if None)
self.qtIfwDirPath = None
# other IFW command line options
self.isDebugMode = False
self.isDebugMode = True
self.otherqtIfwArgs = ""
# Qt C++ Content extended details / requirements
self.isQtCppExe = False
Expand Down Expand Up @@ -160,19 +158,22 @@ class QtIfwConfigXml( _QtIfwXml ):
, "RunProgram" # RunProgramArguments added separately...
, "RunProgramDescription"
]
__ARG_TAG = "Argument"
__RUN_ARGS_TAG = "RunProgramArguments"
__ARG_TAG = "Argument"

def __init__( self, name, exeName, version, publisher,
companyTradeName=None, iconFilePath=None ) :
iconFilePath=None, isGui=True,
companyTradeName=None ) :
_QtIfwXml.__init__( self, QtIfwConfigXml.__ROOT_TAG,
QtIfwConfigXml.__TAGS )

self.exeName = util._normExeName( exeName )
self.exeName = util.normBinaryName( exeName, isGui=isGui )
if IS_LINUX :
# qt installer does not support icon embedding in Linux
iconBaseName = self.iconFilePath = None
else :
self.iconFilePath = iconFilePath
self.iconFilePath = util._normIconName( iconFilePath,
isPathPreserved=True )
try: iconBaseName = splitExt( basename(iconFilePath) )[0]
except: iconBaseName = None
self.companyTradeName = ( companyTradeName if companyTradeName
Expand Down Expand Up @@ -204,8 +205,15 @@ def setDefaultTitle( self ) :
def setDefaultPaths( self ) :
if self.exeName is not None:
# NOTE: THE WORKING DIRECTORY IS NOT SET FOR RUN PROGRAM!
# THERE DOES NOT SEEM TO BE AN OPTION YET FOR THIS IN QT IFW
self.RunProgram = "@TargetDir@/%s" % (self.exeName,)
# THERE DOES NOT SEEM TO BE AN OPTION YET FOR THIS IN QT IFW
programPath = "@TargetDir@/%s" % (self.exeName,)
if util._isMacApp( self.exeName ):
self.RunProgram = util._LAUNCH_MACOS_APP_CMD
if not isinstance( self.runProgramArgList, list ) :
self.runProgramArgList = []
self.runProgramArgList.insert(0, programPath)
else : self.RunProgram = programPath

if (self.companyTradeName is not None) and (self.Name is not None):
self.TargetDir = ( "@ApplicationsDir@/%s/%s" %
(self.companyTradeName, self.Name) )
Expand All @@ -215,8 +223,10 @@ def setDefaultPaths( self ) :

def addCustomTags( self, root ) :
if self.runProgramArgList is not None and self.RunProgram is not None:
runArgs = _QtIfwXmlElement( QtIfwConfigXml.__RUN_ARGS_TAG,
None, root )
for arg in self.runProgramArgList:
_QtIfwXmlElement( QtIfwConfigXml.__ARG_TAG, arg, root )
_QtIfwXmlElement( QtIfwConfigXml.__ARG_TAG, arg, runArgs )

def path( self ) :
return joinPath( BUILD_SETUP_DIR_PATH,
Expand Down Expand Up @@ -322,7 +332,7 @@ def __winAddShortcut( location, exeName,
label="@ProductName@",
directory="@TargetDir@",
iconId=0 ):
exePath = "%s/%s" % (directory, util._normExeName( exeName ))
exePath = "%s/%s" % (directory, util.normBinaryName( exeName ))
locDir = QtIfwPackageScript.__WIN_SHORTCUT_LOCATIONS[location]
shortcutPath = "%s/%s.lnk" % (locDir, label)
s = QtIfwPackageScript.__WIN_ADD_SHORTCUT_TMPLT
Expand All @@ -339,7 +349,7 @@ def __linuxAddDesktopEntry( location, exeName, version,
directory="@TargetDir@",
pngPath=None,
isGui=True ):
exePath = "%s/%s" % (directory, util._normExeName( exeName ))
exePath = "%s/%s" % (directory, util.normBinaryName( exeName ))
locDir = QtIfwPackageScript.__X11_SHORTCUT_LOCATIONS[location]
shortcutPath = "%s/%s.desktop" % (locDir, label.replace(" ","_"))
s = QtIfwPackageScript.__X11_ADD_DESKTOP_ENTRY_TMPLT
Expand All @@ -354,14 +364,16 @@ def __linuxAddDesktopEntry( location, exeName, version,
return s

def __init__( self, pkgName, fileName=DEFAULT_QT_IFW_SCRIPT_NAME,
exeName=None, script=None, srcPath=None ) :
exeName=None, isGui=True,
script=None, scriptPath=None ) :
self.pkgName = pkgName
self.fileName = fileName
if srcPath :
with open( srcPath, 'rb' ) as f: self.script = f.read()
if scriptPath :
with open( scriptPath, 'rb' ) as f: self.script = f.read()
else : self.script = script

self.exeName = exeName
self.isGui = isGui

self.exeVersion = "0.0.0.0"
self.pngIconResPath = None
Expand Down Expand Up @@ -416,11 +428,13 @@ def __genComponentCreateOperationsBody( self ):
if self.exeName and self.isAppShortcut :
x11Ops += QtIfwPackageScript.__linuxAddDesktopEntry(
APPS_X11_SHORTCUT, self.exeName, self.exeVersion,
pngPath=self.pngIconResPath )
pngPath=self.pngIconResPath,
isGui=self.isGui )
if self.exeName and self.isDesktopShortcut:
x11Ops += QtIfwPackageScript.__linuxAddDesktopEntry(
DESKTOP_X11_SHORTCUT, self.exeName, self.exeVersion,
pngPath=self.pngIconResPath )
pngPath=self.pngIconResPath,
isGui=self.isGui )
if x11Ops!="" :
self.componentCreateOperationsBody += (
' if( systemInfo.kernelType === "linux" ){\n' +
Expand Down Expand Up @@ -492,7 +506,7 @@ def __initBuild( qtIfwConfig ) :
print( "Initializing installer build..." )
# remove any prior setup file
setupExePath = joinPath( THIS_DIR,
util._normExeName( qtIfwConfig.setupExeName ) )
util.normBinaryName( qtIfwConfig.setupExeName ) )
if exists( setupExePath ) : removeFile( setupExePath )
# create a "clean" build directory
if exists( BUILD_SETUP_DIR_PATH ) : removeDir( BUILD_SETUP_DIR_PATH )
Expand Down Expand Up @@ -572,12 +586,14 @@ def __build( qtIfwConfig ) :
qtUtilityPath = joinPath( qtIfwConfig.qtIfwDirPath,
joinPath( __BIN_SUB_DIR, __QT_INSTALL_CREATOR_EXE_NAME ) )
setupExePath = joinPath( THIS_DIR,
util._normExeName( qtIfwConfig.setupExeName ) )
util.normBinaryName( qtIfwConfig.setupExeName ) )
cmd = '%s %s "%s"' % ( qtUtilityPath, str(qtIfwConfig), setupExePath )
util._system( cmd )
if IS_MACOS : setupExePath = "%s%s" % (setupExePath, __MACOS_SETUP_EXT)
if exists( setupExePath ) : print( "Created %s!" % (setupExePath,) )
else: raise Exception( "FAILED to create %s" % (setupExePath,) )
util._system( cmd )
setupExePath = normBinaryName( setupExePath,
isPathPreserved=True, isGui=True )
if not exists( setupExePath ) :
raise Exception( 'FAILED to create "%s"' % (setupExePath,) )
print( 'Installer built successfully!\n"%s"!' % (setupExePath,) )
return setupExePath

def __postBuild( qtIfwConfig, isPkgSrcRemoved ): # @UnusedVariable
Expand Down

0 comments on commit 3eeefd9

Please sign in to comment.