scide: implement selectionLength for openDocument
[supercollider.git] / platform / windows / distrowin.py
blob7a295f5120f1c947a2191b327a1b5fb17c23b4f8
1 # distrowin.py
2 # script to generate SuperCollider WIX (windows installer xml) source file from template
3 # Copyright (c) 2008 Dan Stowell. All rights reserved.
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License as
7 # published by the Free Software Foundation; either version 2 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
18 # USA
21 # REQUIREMENTS:
22 # (1) You must have installed the "WiX toolset" and added its "bin" folder to your PATH
23 # (2) You must have run the Visual Studio compilation process to create Psycollider stuff in the "build" folder
24 # (3) This script file, and the wix template, must be in the "windows" folder in SuperCollider3 svn tree (sibling to the "build" folder)
25 # (4) I think you also need to put FFTW and libsndfile DLLs into the "build" folder
27 import os, glob, uuid, re, sys, shutil, zipfile
29 ########################################
30 # Check for SwingOSC, because we definitely want it included :)
31 for detectpath in ('../common/build/SwingOSC.jar', '../common/build/SCClassLibrary/SwingOSC', '../common/build/Help/SwingOSC'):
32 if not os.path.exists(detectpath):
33 print("ERROR:\n Path %s not detected.\n It's required for bundling SwingOSC into the distro." % detectpath)
34 sys.exit(1)
36 ########################################
37 # Run the "py2exe" procedure to build an exe file
39 os.system('cd ../common/Psycollider/Psycollider && python setup.py py2exe')
40 for detectpath in ('../common/Psycollider/Psycollider/dist/Psycollider.exe', '../common/Psycollider/Psycollider/dist/w9xpopen.exe'):
41 if not os.path.exists(detectpath):
42 print("ERROR:\n Path %s not detected.\n Generating executable (using py2exe) probably failed." % detectpath)
43 sys.exit(1)
44 # Also copy PySCLang.pyd out of its "site-packages" location
45 shutil.copy(os.getenv('PYTHONPATH', sys.exec_prefix) + '/Lib/site-packages/PySCLang.pyd', '../common/Psycollider/Psycollider/dist/')
46 # and a dll we need
47 shutil.copy(os.getenv('PYTHONPATH', sys.exec_prefix) + '/Lib/site-packages/wx-2.8-msw-unicode/wx/gdiplus.dll', '../common/Psycollider/Psycollider/dist/')
50 ########################################
51 # Now we start to build up the XML content for WiX
52 xmlstr1 = "" # directory tree
53 xmlstr2 = "" # "feature" contents
55 regex1 = re.compile('[^a-zA-Z0-9.]')
56 def pathToId(path):
57 global regex1
58 id = regex1.sub('_', path.replace('../common/build/', ''))
59 return 's'+id[max(len(id)-64, 0):] # Prepending 's' a bit of a hack to ensure never begins with '3', '_' etc
60 def pathToGuid(path):
61 return str(uuid.uuid3(uuid.NAMESPACE_DNS, 'supercollider.sourceforge.net/' + path))
63 # This recursively scans a directory and builds up the requisite XML for installing the relevant files.
64 def scanDirForWix(path, fileexts, nestlev):
65 global xmlstr1, xmlstr2
66 dircontents = os.listdir(path)
67 for item in dircontents:
68 fullerpath = path + '/' + item
69 if os.path.isdir(fullerpath) and item[0] != '.' and item!='osx' and item!='linux': # the '.' is to exclude .svn
70 # print fullerpath
71 xmlstr1 = xmlstr1 + ' '*nestlev + '<Directory Id="%s" Name="%s">\n' % (pathToId(fullerpath), item)
72 # Recurse:
73 scanDirForWix(fullerpath, fileexts, nestlev+1)
74 xmlstr1 = xmlstr1 + ' '*nestlev + '</Directory>\n'
75 elif os.path.isfile(fullerpath) and not os.path.islink(fullerpath):
76 for fileext in fileexts:
77 if item.lower().endswith(fileexts): #and item matches a certain range of file extensions:
78 # print fullerpath + " --- FILE"
79 compId = pathToId(fullerpath)
80 xmlstr1 = xmlstr1 + ' '*nestlev + '<Component Id="%s" Guid="%s">\n' % (compId, pathToGuid(fullerpath))
81 xmlstr1 = xmlstr1 + ' '*nestlev + ' <File Id="%s" Name="%s" Source="%s" DiskId="1"/>\n' % \
82 (compId + '.file', item, fullerpath)
83 xmlstr1 = xmlstr1 + ' '*nestlev + '</Component>\n'
84 xmlstr2 = xmlstr2 + ' <ComponentRef Id="%s" />\n' % compId
85 break
86 #else:
87 # print 'Ignored %s\n' % fullerpath
89 # Now we do all the different scans we want
91 xmlstr1 = xmlstr1 + '<DirectoryRef Id="SCpluginsFolder">\n'
92 xmlstr2 = xmlstr2 + '<Feature Id="CorePluginsFeature" Title="Server plugins" Description="Core set of SC3 plugins" Level="1">\n'
93 scanDirForWix('../common/build/plugins', ('.scx'), 0)
94 xmlstr2 = xmlstr2 + '</Feature>\n'
95 xmlstr1 = xmlstr1 + '</DirectoryRef>\n\n'
97 xmlstr1 = xmlstr1 + '<DirectoryRef Id="SCHelpFolder">\n'
98 xmlstr2 = xmlstr2 + '<Feature Id="HelpFilesFeature" Title="Help files" Description="SC3 help documentation" Level="1">\n'
99 scanDirForWix('../common/build/Help', ('.html', '.htm', '.rtf', '.rtfd', '.jpg', '.png', '.gif', '.scd'), 0)
100 xmlstr2 = xmlstr2 + '</Feature>\n'
101 xmlstr1 = xmlstr1 + '</DirectoryRef>\n\n'
103 includeExtras = False # whether or not to expect build/sc3-plugins and to bundle it into the extensions folder
105 xmlstr1 = xmlstr1 + '<DirectoryRef Id="SCextensionsFolder">\n'
106 if includeExtras:
107 xmlstr1 = xmlstr1 + ' <Component Id="SCextensions" Guid="35AF303A-C836-11DD-84E5-084C56D89593">\n'
108 xmlstr1 = xmlstr1 + ' </Component>\n'
109 xmlstr1 = xmlstr1 + '<Directory Id="sc3plugins" Name="sc3-plugins">\n'
110 xmlstr2 = xmlstr2 + '<Feature Id="Sc3PluginsFeature" Title="Community sc3-plugins pack" Description="Third-party plugins pack sc3-plugins" Level="1">\n'
111 scanDirForWix('../common/build/sc3-plugins', ('.html', '.htm', '.rtf', '.rtfd', '.jpg', '.png', '.gif', '.scd', '.scx', '.sc'), 0)
112 xmlstr2 = xmlstr2 + '</Feature>\n'
113 xmlstr1 = xmlstr1 + '</Directory>\n\n'
114 else:
115 xmlstr1 = xmlstr1 + ' <Component Id="SCextensions" Guid="35AF303A-C836-11DD-84E5-084C56D89593">\n'
116 xmlstr1 = xmlstr1 + ' <CreateFolder/>\n' # This is how to create an empty folder in wix
117 xmlstr1 = xmlstr1 + ' </Component>\n'
118 xmlstr1 = xmlstr1 + '</DirectoryRef>\n\n'
120 xmlstr1 = xmlstr1 + '<DirectoryRef Id="SCsoundsFolder">\n'
121 xmlstr2 = xmlstr2 + '<Feature Id="SoundFilesFeature" Title="Sound files" Description="Some audio files" Level="1">\n'
122 scanDirForWix("../common/build/sounds", (".aiff", ".wav", ".aif"), 0)
123 xmlstr2 = xmlstr2 + '</Feature>\n'
124 xmlstr1 = xmlstr1 + '</DirectoryRef>\n\n'
126 xmlstr1 = xmlstr1 + '<DirectoryRef Id="SCClassLibrary">\n'
127 xmlstr2 = xmlstr2 + '<Feature Id="SCClassLibraryFeature" Title="SC3 class files" Description="The classes which define the SuperCollider language" Level="1">\n'
128 scanDirForWix("../common/build/SCClassLibrary", (".sc"), 0)
129 xmlstr2 = xmlstr2 + '</Feature>\n'
130 xmlstr1 = xmlstr1 + '</DirectoryRef>\n\n'
133 # WORKAROUND FOR M$ BUG:
134 # Windows installer is supposed to be able to handle massive numbers of files, but actually it fucks up if a <Feature> contains more than around 1000 files.
135 # See http://www.add-in-express.com/creating-addins-blog/2007/11/12/windows-installer-error-2908/
136 # Because of this, we need to artificially split the helpfiles feature in two.
137 xmlstr2b = xmlstr2.split('<ComponentRef Id="Help_Style_Guide', 1)
138 if not len(xmlstr2b) == 2:
139 print "Warning, unable to break up the XML string as expected."
140 else:
141 xmlstr2 = xmlstr2b[0] + '</Feature>\n<Feature Id="HelpFilesFeaturePT2" Title="Help files, part 2" Description="SC3 help documentation" Level="1">\n<ComponentRef Id="Help_Style_Guide' + xmlstr2b[1]
143 # OK, now we have the XML fragments, we want to substitute them into the XML template file
144 template = ''
145 templatef = open('sc3-win-installer-template.wxs', 'r')
146 for line in templatef:
147 template = template + line
148 templatef.close()
150 template = template.split('<!-- SUBST:SPLITHERE -->');
152 f = open('supercollider-installer.wxs', 'w')
153 f.write(template[0])
154 f.write(xmlstr1)
155 f.write(template[1])
156 f.write(xmlstr2)
157 f.write(template[2])
158 f.close()
160 print "\ndistrowin.py: done generating WiX file\n"
162 print "Calling WiX compile/link steps...\n"
163 os.system('candle supercollider-installer.wxs')
164 os.system('light -ext WixUIExtension -cultures:en-us supercollider-installer.wixobj')
166 print "\ndistrowin.py: done building MSI\n"
167 print "\ndistrowin.py: now to bundle a zip file\n"
169 z = zipfile.ZipFile('supercollider-installer.zip', 'w', zipfile.ZIP_DEFLATED)
170 z.write('supercollider-installer.msi')
171 z.write('INSTALL.txt')
172 z.write('../COPYING', 'COPYING.txt')
173 z.write('copyright_info_forwinbundle.txt', 'copyright info.txt')
174 z.close()
177 print "\ndistrowin.py: done\n"