11 from bockbuild
.darwinprofile
import DarwinProfile
12 from bockbuild
.util
.util
import *
15 class MonoReleaseProfile(DarwinProfile
):
16 description
= 'The Mono Framework for MacOS'
41 'ige-mac-integration',
56 'pcl-reference-assemblies',
66 def attach (self
, bockbuild
):
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
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'):
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
:
131 self
.gcc_flags
.extend(['-O2'])
133 # THIS IS THE MAIN METHOD FOR MAKING A PACKAGE
135 self
.fix_gtksharp_configs()
136 self
.verify_binaries()
138 working
= self
.setup_working_dir()
139 uninstall_script
= os
.path
.join(working
, "uninstallMono.sh")
142 self
.apply_blacklist(working
, 'mdk_blacklist.sh')
143 self
.make_updateinfo(working
, self
.MDK_GUID
)
144 mdk_pkg
= self
.run_pkgbuild(working
, "MDK")
146 # self.make_dmg(mdk_dmg, title, mdk_pkg, uninstall_script)
148 shutil
.rmtree(working
)
150 def calculate_updateid(self
):
151 # Create the updateid
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
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
))
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")
186 ("include", "Headers"),
187 ("lib", "Libraries"),
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
196 if os
.path
.exists(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
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")
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
):
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)
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
,
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
,
274 run_shell(productbuild_cmd
)
276 assert_exists(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
294 if arch
== "darwin-32":
296 elif arch
== "darwin-64":
298 elif arch
== "darwin-universal":
299 arch_str
= "universal"
301 error ("Unknown architecture")
303 if self
.bockbuild
.cmd_options
.release_build
:
304 info
= (pkg_type
, self
.FULL_VERSION
, arch_str
)
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
315 def fix_line(self
, line
, matcher
):
316 def insert_install_root(matches
):
318 captures
= matches
.groupdict()
319 return 'target="%s"' % os
.path
.join(root
, "lib", captures
["lib"])
322 pattern
= r
'target="(?P<lib>.+\.dylib)"'
323 result
= re
.sub(pattern
, insert_install_root
, 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
:
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...',
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
):
353 self
.fix_dllmap(c
, lambda line
: "dllmap" in line
)
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
)
363 token
= match
.group(1)
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
):
372 f
= os
.path
.join(path
, name
)
373 file_type
= backtick('file "%s"' % f
)
374 if "Mach-O executable" in "".join(file_type
):
378 envscript
= '''#!/bin/sh
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 @ "
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
:
398 os
.chmod(path
, os
.stat(path
).st_mode | stat
.S_IEXEC
)
400 subprocess
.call(['bash', '-c', path
])