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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
#!/usr/bin/env python
# coding=utf-8
"""
A setup file to build Frescobaldi.app with py2app.
Use the '-h' flag to see the usage notes.
"""
import argparse
import os
import sys
from setuptools import setup
import shutil
from subprocess import Popen
# Python 2 text strings: basestring = str (ASCII) + unicode (Unicode)
# Python 3 text strings: str (Unicode)
# See https://docs.python.org/3/howto/pyporting.html for details.
try:
string_types = basestring
except NameError:
string_types = str
macosx = os.path.realpath(os.path.dirname(__file__))
root = os.path.dirname(macosx)
sys.path.insert(0, root)
from frescobaldi_app import toplevel
toplevel.install()
import appinfo
try:
from portmidi import pm_ctypes
dylib_name = pm_ctypes.dll_name
except ImportError:
dylib_name = None
icon = '{0}/icons/{1}.icns'.format(macosx, appinfo.name)
ipstrings = '{0}/app_resources/InfoPlist.strings'.format(macosx)
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-f', '--force', action = 'store_true', \
help = 'force execution even if SCRIPT does not exist')
parser.add_argument('-v', '--version', \
help = 'version string for the application bundle, \
visible e.g. in \'Get Info\' and in \'Open with...\'', default = appinfo.version)
parser.add_argument('-s', '--script', \
help = 'path of {0}\'s main script; you should use an absolute path, \
so that the application bundle can be moved to another \
directory'.format(appinfo.appname), default = '{0}/{1}'.format(root, appinfo.name))
parser.add_argument('-a', '--standalone', action = 'store_true', \
help = 'build a standalone application bundle \
(WARNING: some manual steps are required after the execution of this script)')
parser.add_argument('-p', '--portmidi', \
help = 'full path of PortMIDI library (used only with \'-a\')', \
default = dylib_name)
parser.add_argument('-r', '--arch', \
help = 'architecture set to include: x86_64, arm64, universal2; \
if the value is None, the architecture of the current Python binary is used \
(used only with \'-a\')')
args = parser.parse_args()
if not (os.path.isfile(args.script) or args.force):
sys.exit('Error: \'{0}\' does not exist or is not a file.\n\
If you really want to point the application bundle to \'{0}\',\n\
use the \'-f\' or \'--force\' flag.'.format(args.script))
if args.standalone and not (isinstance(args.portmidi, string_types) and os.path.isfile(args.portmidi)):
sys.exit('Error: \'{0}\' does not exist or is not a file.'.format(args.portmidi))
plist = dict(
CFBundleName = appinfo.appname,
CFBundleDisplayName = appinfo.appname,
CFBundleShortVersionString = args.version,
CFBundleVersion = args.version,
CFBundleExecutable = appinfo.appname,
CFBundleIdentifier = 'org.{0}.{0}'.format(appinfo.name),
CFBundleIconFile = '{0}.icns'.format(appinfo.name),
NSHumanReadableCopyright = u'Copyright © 2008-2023 Wilbert Berendsen.',
CFBundleDocumentTypes = [
{
'CFBundleTypeExtensions': ['ly', 'lyi', 'ily'],
'CFBundleTypeName': 'LilyPond file',
'CFBundleTypeRole': 'Editor',
},
{
'CFBundleTypeExtensions': ['tex', 'lytex', 'latex'],
'CFBundleTypeName': 'LaTeX file',
'CFBundleTypeRole': 'Editor',
},
{
'CFBundleTypeExtensions': ['docbook', 'lyxml'],
'CFBundleTypeName': 'DocBook file',
'CFBundleTypeRole': 'Editor',
},
{
'CFBundleTypeExtensions': ['html'],
'CFBundleTypeName': 'HTML file',
'CFBundleTypeRole': 'Editor',
'LSItemContentTypes': ['public.html']
},
{
'CFBundleTypeExtensions': ['xml'],
'CFBundleTypeName': 'XML file',
'CFBundleTypeRole': 'Editor',
'LSItemContentTypes': ['public.xml']
},
{
'CFBundleTypeExtensions': ['itely', 'tely', 'texi', 'texinfo'],
'CFBundleTypeName': 'Texinfo file',
'CFBundleTypeRole': 'Editor',
},
{
'CFBundleTypeExtensions': ['scm'],
'CFBundleTypeName': 'Scheme file',
'CFBundleTypeRole': 'Editor',
},
{
'CFBundleTypeExtensions': ['*'],
'CFBundleTypeName': 'Text file',
'CFBundleTypeRole': 'Editor',
'LSItemContentTypes': ['public.text']
}
]
)
options = {
'argv_emulation': True,
'plist': plist
}
if args.standalone:
options.update({
'packages': ['frescobaldi_app'],
'frameworks': [args.portmidi],
})
if args.arch:
options.update({
'arch': args.arch
})
try:
patchlist = [f for f in os.listdir('patch') if f.endswith(".diff")]
except OSError:
patchlist = []
for patchfile in patchlist:
with open('patch/{0}'.format(patchfile), 'r') as input:
Popen(["patch", "-d..", "-p0"], stdin=input)
else:
options.update({
'semi_standalone': True,
'alias': True
})
setup(
app = [args.script],
name = appinfo.appname,
options = {'py2app': options},
setup_requires = ['py2app'],
script_args = ['py2app']
)
app_resources = 'dist/{0}.app/Contents/Resources'.format(appinfo.appname)
icon_dest = '{0}/{1}.icns'.format(app_resources, appinfo.name)
print('copying file {0} -> {1}'.format(icon, icon_dest))
shutil.copyfile(icon, icon_dest)
os.chmod(icon_dest, 0o0644)
locales = ['cs', 'de', 'en', 'es', 'fr', 'gl', 'it', 'nl', 'pl', 'pt', 'ru', 'tr', 'uk', 'zh_CN', 'zh_HK', 'zh_TW']
for l in locales:
app_lproj = '{0}/{1}.lproj'.format(app_resources, l)
os.mkdir(app_lproj, 0o0755)
ipstrings_dest = '{0}/InfoPlist.strings'.format(app_lproj)
print('copying file {0} -> {1}'.format(ipstrings, ipstrings_dest))
shutil.copyfile(ipstrings, ipstrings_dest)
os.chmod(ipstrings_dest, 0o0644)
if args.standalone:
if patchlist:
print('reversing patches:')
for patchfile in patchlist:
with open('patch/{0}'.format(patchfile), 'r') as input:
Popen(["patch", "-R", "-d..", "-p0"], stdin=input)
|