freeze.py 4.38 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#! python

# This script freezes Frescobaldi to a standalone application without
# needing to install any dependencies.
#
# Usage:
# C:\Python27\Python freeze.py
#
# How it works:
# It creates, using cx_Freeze, a frescobaldi executable inside the frozen/
# directory, along with all used (manually specified) Python modules.
# Then the whole frescobaldi_app directory is copied and the Python scripts
# byte-compiled.
# Finally, an installer is created using the Inno Setup console-mode compiler.

# the Inno Setup console-mode compiler
iscc = 'c:\\Program Files\\Inno Setup 5\\ISCC'

# where to build the frozen program folder
target_dir = 'frozen'

# import standard modules and cx_Freeze
import imp
import os
import py_compile
import shutil
import subprocess
import sys
from cx_Freeze import Executable, Freezer

31 32 33
# access the frescobaldi_app package
sys.path.insert(0, '..')

34
# access meta-information such as version, etc.
35
from frescobaldi_app import appinfo
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

# find pypm by adding the dir of pygame to sys.path
sys.path.append(imp.find_module('pygame')[1])

includes = [
    'sip',
    'PyQt4.QtCore',
    'PyQt4.QtGui',
    'PyQt4.QtWebKit',
    'PyQt4.QtNetwork',
    'PyQt4.QtSvg',
    'PyQt4.QtXml',
    'popplerqt4',
    'pypm',
    
    '__future__',
52
    'argparse',
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
    'bisect',
    'contextlib',
    'difflib',
    'fractions',
    'glob',
    'json',
    'itertools',
    'functools',
    'optparse',
    'os',
    'platform',
    're',
    'sys',
    'shutil',
    'struct',
    'subprocess',
    'traceback',
    'types',
    'unicodedata',
    'weakref',
    'xml.etree.ElementTree',
]

76 77 78 79
packages = [
    'ly',
]

80 81 82 83
excludes = [
    'frescobaldi_app',  # we'll add this one manually
]

84 85 86
# be sure the target dir is removed
shutil.rmtree(target_dir, ignore_errors = True)

87
frescobaldi = Executable(
88 89
    '../frescobaldi',
    icon = '../frescobaldi_app/icons/frescobaldi.ico',
90 91 92 93 94 95 96
    appendScriptToExe = True,
    base = 'Win32GUI', # no console
)

f = Freezer(
    [frescobaldi],
    includes = includes,
97
    packages = packages,
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
    excludes = excludes,
    targetDir = target_dir,
    copyDependentFiles = True,
    compress = False,
    # silent = True,
)

f.Freeze()

def copy_plugins(name):
    """Copies a folder from the Qt4 plugins directory."""
    path = imp.find_module('PyQt4')[1]
    folder = os.path.join(path, 'plugins', name)
    target = os.path.join(target_dir, name)
    shutil.rmtree(target, ignore_errors = True)
    shutil.copytree(folder, target)

# copy Qt4 imageformat plugins
copy_plugins('imageformats')

# copy Qt4 iconengine plugins
copy_plugins('iconengines')

# copy the frescobaldi_app directory
122 123 124 125
subprocess.call(
    [sys.executable, 'setup.py', 'build_py',
     '--build-lib', os.path.join('windows', target_dir), '--compile'],
    cwd="..")
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143

# make an Inno Setup installer
inno_script = b'''
[Setup]
AppName=Frescobaldi
AppVersion={version}
AppVerName=Frescobaldi {version}
AppPublisher={author}
AppPublisherURL={homepage}
AppComments={comments}

DefaultDirName={{pf}}\\Frescobaldi
DefaultGroupName=Frescobaldi
UninstallDisplayIcon={{app}}\\frescobaldi.exe
Compression=lzma2
SolidCompression=yes

SourceDir={target}\\
144
OutputDir=..\\..\\dist\\
145 146
OutputBaseFilename="Frescobaldi Setup {version}"
SetupIconFile=frescobaldi_app\\icons\\frescobaldi.ico
147
LicenseFile=..\\..\\COPYING
148 149 150
WizardImageFile=..\\frescobaldi-wininst.bmp
WizardImageStretch=no

151 152 153
[InstallDelete]
Type: filesandordirs; Name: "{{app}}\\frescobaldi_app"

154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
[Files]
Source: "*.*"; DestDir: "{{app}}"; Flags: recursesubdirs;

[Icons]
Name: "{{group}}\Frescobaldi"; Filename: "{{app}}\\frescobaldi.exe";

[Tasks]
Name: assocly; Description: "{{cm:AssocFileExtension,Frescobaldi,.ly}}";

[Registry]
Root: HKCR; Subkey: "LilyPond\\shell\\frescobaldi";\
 ValueType: string; ValueName: ""; ValueData: "Edit with &Frescobaldi...";\
 Flags: uninsdeletekey
Root: HKCR; Subkey: "LilyPond\\shell\\frescobaldi\\command";\
 ValueType: string; ValueName: ""; ValueData: """{{app}}\\frescobaldi.exe"" ""%1"""
Tasks: assocly; Root: HKCR; Subkey: "LilyPond\\shell";\
 ValueType: string; ValueName: ""; ValueData: "frescobaldi";

[Run]
Filename: "{{app}}\\frescobaldi.exe";\
 Description: {{cm:LaunchProgram,Frescobaldi}};\
 Flags: postinstall nowait skipifsilent;

'''.format(
178 179 180 181
    version=appinfo.version,
    homepage=appinfo.url,
    author=appinfo.maintainer,
    comments=appinfo.description,
182 183 184 185 186
    target=target_dir,
)

subprocess.Popen([iscc, '-'], stdin=subprocess.PIPE).communicate(inno_script)