[System.Net.Http] Add Transfer-Encoding: chunked special handling. Fixes #47599
[mono-project.git] / packaging / MacSDK / profile.py
blob270b70d0254209b33c08d5fa6e50c003ba0d8fdf
1 import itertools
2 import os
3 import re
4 import shutil
5 import string
6 import sys
7 import tempfile
8 import subprocess
9 import stat
11 from bockbuild.darwinprofile import DarwinProfile
12 from bockbuild.util.util import *
13 from glob import glob
15 class MonoReleaseProfile(DarwinProfile):
16 description = 'The Mono Framework for MacOS'
17 packages = [
18 'gettext',
19 'pkg-config',
21 # Base Libraries
22 'libpng',
23 'libjpeg',
24 'libtiff',
25 'libgif',
26 'libxml2',
27 'freetype',
28 'fontconfig',
29 'pixman',
30 'cairo',
31 'libffi',
32 'glib',
33 'pango',
34 'atk',
35 'intltool',
36 'gdk-pixbuf',
37 'gtk+',
38 'libglade',
39 'sqlite',
40 'expat',
41 'ige-mac-integration',
43 # Theme
44 'libcroco',
45 'librsvg',
46 'hicolor-icon-theme',
47 'gtk-engines',
48 'murrine',
49 'xamarin-gtk-theme',
50 'gtk-quartz-engine',
52 # Mono
53 'mono-llvm',
54 'mono',
55 'msbuild',
56 'pcl-reference-assemblies',
57 'libgdiplus',
58 'xsp',
59 'gtk-sharp',
60 'ironlangs',
61 'fsharp',
62 'mono-basic',
63 'nuget'
66 def attach (self, bockbuild):
67 self.min_version = 7
68 DarwinProfile.attach (self, bockbuild)
70 # quick disk space check (http://stackoverflow.com/questions/787776/)
71 s = os.statvfs(bockbuild.root)
72 free_space = (s.f_bavail * s.f_frsize) / (1024 * 1024 * 1024) # in GB
74 if free_space < 10:
75 error('Low disk space (less than 10GB), aborting')
77 # check for XQuartz installation (needed for libgdiplus)
78 if not os.path.exists('/opt/X11/include/X11/Xlib.h'):
79 error(
80 'XQuartz is required to be installed (download from http://xquartz.macosforge.org/) ')
82 self.MONO_ROOT = "/Library/Frameworks/Mono.framework"
83 self.BUILD_NUMBER = "0"
84 self.MDK_GUID = "964ebddd-1ffe-47e7-8128-5ce17ffffb05"
86 system_mono_dir = '/Library/Frameworks/Mono.framework/Versions/Current'
87 self.env.set('system_mono', os.path.join(
88 system_mono_dir, 'bin', 'mono'))
89 self.env.set('system_mcs', os.path.join(system_mono_dir, 'bin', 'mcs'))
91 self.env.set('system_mono_version', backtick(
92 '%s --version' % self.env.system_mono)[0])
94 # config overrides for some programs to be functional while staged
96 self.env.set('GDK_PIXBUF_MODULE_FILE',
97 '%{staged_prefix}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache')
98 self.env.set('GDK_PIXBUF_MODULEDIR',
99 '%{staged_prefix}/lib/gdk-pixbuf-2.0/2.10.0/loaders')
100 self.env.set('PANGO_SYSCONFDIR', '%{staged_prefix}/etc')
101 self.env.set('PANGO_LIBDIR', '%{staged_prefix}/lib')
102 # self.env.set ('MONO_PATH', '%{staged_prefix}/lib/mono/4.0')
103 self.debug_info = ['gtk+', 'cairo',
104 'pango', 'mono', 'llvm', 'libgdiplus']
105 self.cache_host = None
107 def setup_release(self):
108 self.mono_package = self.release_packages['mono']
109 dest = os.path.join(self.bockbuild.build_root, self.mono_package.source_dir_name)
110 self.mono_package.fetch(dest)
113 verbose('Mono version: %s' % self.mono_package.version)
114 self.RELEASE_VERSION = self.mono_package.version
115 self.prefix = os.path.join(
116 self.MONO_ROOT, "Versions", self.RELEASE_VERSION)
118 if os.path.exists(self.prefix):
119 error('Prefix %s exists, and may interfere with the staged build. Please remove and try again.' % self.prefix)
121 self.calculate_updateid()
123 self.mono_package.custom_version_str = self.FULL_VERSION
124 trace(self.package_info('MDK'))
126 self.dont_optimize = ['pixman']
128 for p in self.release_packages.values():
129 if p.name in self.dont_optimize:
130 continue
131 self.gcc_flags.extend(['-O2'])
133 # THIS IS THE MAIN METHOD FOR MAKING A PACKAGE
134 def package(self):
135 self.fix_gtksharp_configs()
136 self.verify_binaries()
138 working = self.setup_working_dir()
139 uninstall_script = os.path.join(working, "uninstallMono.sh")
141 # make the MDK
142 self.apply_blacklist(working, 'mdk_blacklist.sh')
143 self.make_updateinfo(working, self.MDK_GUID)
144 mdk_pkg = self.run_pkgbuild(working, "MDK")
145 title(mdk_pkg)
146 # self.make_dmg(mdk_dmg, title, mdk_pkg, uninstall_script)
148 shutil.rmtree(working)
150 def calculate_updateid(self):
151 # Create the updateid
152 pwd = os.getcwd()
153 git_bin = self.bockbuild.git_bin
154 trace("cur path is %s and git is %s" % (pwd, git_bin))
155 blame_rev_str = 'cd %s; %s blame configure.ac HEAD | grep AC_INIT | sed \'s/ .*//\' ' % (
156 self.mono_package.workspace, git_bin)
157 blame_rev = backtick(blame_rev_str)[0]
158 trace("Last commit to the version string %s" % (blame_rev))
159 version_number_str = 'cd %s; %s log %s..HEAD --oneline | wc -l | sed \'s/ //g\'' % (
160 self.mono_package.workspace, git_bin, blame_rev)
161 self.BUILD_NUMBER = backtick(version_number_str)[0]
162 trace("Calculating commit distance, %s" % (self.BUILD_NUMBER))
163 self.FULL_VERSION = self.RELEASE_VERSION + "." + self.BUILD_NUMBER
164 os.chdir(pwd)
166 parts = self.RELEASE_VERSION.split(".")
167 version_list = (parts + ["0"] * (3 - len(parts)))[:4]
168 for i in range(1, 3):
169 version_list[i] = version_list[i].zfill(2)
170 self.updateid = "".join(version_list)
171 self.updateid += self.BUILD_NUMBER.replace(
172 ".", "").zfill(9 - len(self.updateid))
173 trace(self.updateid)
175 # creates and returns the path to a working directory containing:
176 # PKGROOT/ - this root will be bundled into the .pkg and extracted at /
177 # uninstallMono.sh - copied onto the DMG
178 # Info{_sdk}.plist - used by packagemaker to make the installer
179 # resources/ - other resources used by packagemaker for the installer
180 def setup_working_dir(self):
181 def make_package_symlinks(root):
182 os.symlink(self.prefix, os.path.join(root, "Versions", "Current"))
183 currentlink = os.path.join(self.MONO_ROOT, "Versions", "Current")
184 links = [
185 ("bin", "Commands"),
186 ("include", "Headers"),
187 ("lib", "Libraries"),
188 ("", "Home"),
189 (os.path.join("lib", "libmono-2.0.dylib"), "Mono")
191 for srcname, destname in links:
192 src = os.path.join(currentlink, srcname)
193 dest = os.path.join(root, destname)
194 # If the symlink exists, we remove it so we can create a fresh
195 # one
196 if os.path.exists(dest):
197 os.unlink(dest)
198 os.symlink(src, dest)
200 tmpdir = tempfile.mkdtemp()
201 monoroot = os.path.join(tmpdir, "PKGROOT", self.MONO_ROOT[1:])
202 versions = os.path.join(monoroot, "Versions")
203 os.makedirs(versions)
205 print "Setting up temporary package directory:", tmpdir
207 # setup metadata
208 self.packaging_dir = os.path.join(self.directory, "packaging")
209 run_shell('rsync -aPq %s/* %s' % (self.packaging_dir, tmpdir), False)
211 packages_list = string.join(
212 [pkg.desc for pkg in self.release_packages.values()], "\\\n")
213 deps_list = 'bockbuild (rev. %s)\\\n' % bockbuild.bockbuild_rev + string.join(
214 [pkg.desc for pkg in self.toolchain_packages.values()], "\\\n")
216 parameter_map = {
217 '@@MONO_VERSION@@': self.RELEASE_VERSION,
218 '@@MONO_RELEASE@@': self.BUILD_NUMBER,
219 '@@MONO_VERSION_RELEASE@@': self.RELEASE_VERSION + '_' + self.BUILD_NUMBER,
220 '@@MONO_CSDK_GUID@@': self.MDK_GUID,
221 '@@MONO_VERSION_RELEASE_INT@@': self.updateid,
222 '@@PACKAGES@@': packages_list,
223 '@@DEP_PACKAGES@@': deps_list
225 for dirpath, d, files in os.walk(tmpdir):
226 for name in files:
227 if not name.startswith('.'):
228 replace_in_file(os.path.join(dirpath, name), parameter_map)
230 make_package_symlinks(monoroot)
232 # copy to package root
233 run_shell('rsync -aPq "%s"/* "%s/%s"' %
234 (bockbuild.package_root, versions, self.RELEASE_VERSION), False)
236 return tmpdir
238 def apply_blacklist(self, working_dir, blacklist_name):
239 print "Applying blacklist script:", blacklist_name
240 blacklist = os.path.join(self.packaging_dir, blacklist_name)
241 root = os.path.join(working_dir, "PKGROOT", self.prefix[1:])
242 run_shell('%s "%s" > /dev/null' % (blacklist, root), print_cmd=False)
244 def run_pkgbuild(self, working_dir, package_type):
245 print 'Running pkgbuild & productbuild...',
246 info = self.package_info(package_type)
247 output = os.path.join(self.directory, info["filename"])
248 identifier = "com.xamarin.mono-" + info["type"] + ".pkg"
249 resources_dir = os.path.join(working_dir, "resources")
250 distribution_xml = os.path.join(resources_dir, "distribution.xml")
252 old_cwd = os.getcwd()
253 os.chdir(working_dir)
254 pkgbuild = "/usr/bin/pkgbuild"
255 pkgbuild_cmd = ' '.join([pkgbuild,
256 "--identifier " + identifier,
257 "--root '%s/PKGROOT'" % working_dir,
258 "--version '%s'" % self.RELEASE_VERSION,
259 "--install-location '/'",
260 "--scripts '%s'" % resources_dir,
261 "--quiet",
262 os.path.join(working_dir, "mono.pkg")])
264 run_shell(pkgbuild_cmd)
266 productbuild = "/usr/bin/productbuild"
267 productbuild_cmd = ' '.join([productbuild,
268 "--resources %s" % resources_dir,
269 "--distribution %s" % distribution_xml,
270 "--package-path %s" % working_dir,
271 "--quiet",
272 output])
274 run_shell(productbuild_cmd)
276 assert_exists(output)
277 os.chdir(old_cwd)
278 print output
279 return output
281 def make_updateinfo(self, working_dir, guid):
282 updateinfo = os.path.join(
283 working_dir, "PKGROOT", self.prefix[1:], "updateinfo")
284 with open(updateinfo, "w") as updateinfo:
285 updateinfo.write(guid + ' ' + self.updateid + "\n")
286 version_file = os.path.join(
287 working_dir, "PKGROOT", self.prefix[1:], "VERSION")
288 with open(version_file, "w") as version_file:
289 version_file.write(self.FULL_VERSION + "\n")
291 def package_info(self, pkg_type):
292 arch = self.bockbuild.cmd_options.arch
293 arch_str = None
294 if arch == "darwin-32":
295 arch_str = "x86"
296 elif arch == "darwin-64":
297 arch_str = "x64"
298 elif arch == "darwin-universal":
299 arch_str = "universal"
300 else:
301 error ("Unknown architecture")
303 if self.bockbuild.cmd_options.release_build:
304 info = (pkg_type, self.FULL_VERSION, arch_str)
305 else:
306 info = (pkg_type, '%s-%s' % (git_shortid(self.bockbuild,
307 self.mono_package.workspace), self.FULL_VERSION), arch_str)
309 filename = "MonoFramework-%s-%s.macos10.xamarin.%s.pkg" % info
310 return {
311 "type": pkg_type,
312 "filename": filename
315 def fix_line(self, line, matcher):
316 def insert_install_root(matches):
317 root = self.prefix
318 captures = matches.groupdict()
319 return 'target="%s"' % os.path.join(root, "lib", captures["lib"])
321 if matcher(line):
322 pattern = r'target="(?P<lib>.+\.dylib)"'
323 result = re.sub(pattern, insert_install_root, line)
324 return result
325 else:
326 return line
328 def fix_dllmap(self, config, matcher):
329 handle, temp = tempfile.mkstemp()
330 with open(config) as c:
331 with open(temp, "w") as output:
332 for line in c:
333 output.write(self.fix_line(line, matcher))
334 os.rename(temp, config)
335 os.system('chmod a+r %s' % config)
337 def fix_gtksharp_configs(self):
338 print 'Fixing GTK# configuration files...',
339 count = 0
340 libs = [
341 'atk-sharp',
342 'gdk-sharp',
343 'glade-sharp',
344 'glib-sharp',
345 'gtk-dotnet',
346 'gtk-sharp',
347 'pango-sharp'
349 gac = os.path.join(bockbuild.package_root, "lib", "mono", "gac")
350 confs = [glob.glob(os.path.join(gac, x, "*", "*.dll.config")) for x in libs]
351 for c in itertools.chain(*confs):
352 count = count + 1
353 self.fix_dllmap(c, lambda line: "dllmap" in line)
354 print count
356 def verify(self, f):
357 result = " ".join(backtick("otool -L " + f))
358 regex = os.path.join(self.MONO_ROOT, "Versions", r"(\d+\.\d+\.\d+)")
360 match = re.search(regex, result)
361 if match is None:
362 return
363 token = match.group(1)
364 trace(token)
365 if self.RELEASE_VERSION not in token:
366 raise Exception("%s references Mono %s\n%s" % (f, token, text))
368 def verify_binaries(self):
369 bindir = os.path.join(bockbuild.package_root, "bin")
370 for path, dirs, files in os.walk(bindir):
371 for name in files:
372 f = os.path.join(path, name)
373 file_type = backtick('file "%s"' % f)
374 if "Mach-O executable" in "".join(file_type):
375 self.verify(f)
377 def shell(self):
378 envscript = '''#!/bin/sh
379 PROFNAME="%s"
380 INSTALLDIR="%s"
381 ROOT="%s"
382 export DYLD_FALLBACK_LIBRARY_PATH="$INSTALLDIR/lib:/lib:/usr/lib"
383 export ACLOCAL_PATH="$INSTALLDIR/share/aclocal"
384 export CONFIG_SITE="$INSTALLDIR/$PROFNAME-config.site"
385 export MONO_GAC_PREFIX="$INSTALLDIR"
386 export MONO_ADDINS_REGISTRY="$ROOT/addinreg"
387 export MONO_INSTALL_PREFIX="$INSTALLDIR"
389 export PS1="\[\e[1;3m\][$PROFNAME] \w @ "
390 bash -i
391 ''' % (self.profile_name, self.staged_prefix, self.root)
393 path = os.path.join(self.root, self.profile_name + '.sh')
395 with open(path, 'w') as f:
396 f.write(envscript)
398 os.chmod(path, os.stat(path).st_mode | stat.S_IEXEC)
400 subprocess.call(['bash', '-c', path])
402 MonoReleaseProfile()