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()
122 trace(self
.package_info('MDK'))
124 self
.dont_optimize
= ['pixman']
126 for p
in self
.release_packages
.values():
127 if p
.name
in self
.dont_optimize
:
129 self
.gcc_flags
.extend(['-O2'])
131 # THIS IS THE MAIN METHOD FOR MAKING A PACKAGE
133 self
.fix_gtksharp_configs()
134 self
.verify_binaries()
136 working
= self
.setup_working_dir()
137 uninstall_script
= os
.path
.join(working
, "uninstallMono.sh")
140 self
.apply_blacklist(working
, 'mdk_blacklist.sh')
141 self
.make_updateinfo(working
, self
.MDK_GUID
)
142 mdk_pkg
= self
.run_pkgbuild(working
, "MDK")
144 # self.make_dmg(mdk_dmg, title, mdk_pkg, uninstall_script)
146 shutil
.rmtree(working
)
148 def calculate_updateid(self
):
149 # Create the updateid
151 git_bin
= self
.bockbuild
.git_bin
152 trace("cur path is %s and git is %s" % (pwd
, git_bin
))
153 blame_rev_str
= 'cd %s; %s blame configure.ac HEAD | grep AC_INIT | sed \'s/ .*//\' ' % (
154 self
.mono_package
.workspace
, git_bin
)
155 blame_rev
= backtick(blame_rev_str
)[0]
156 trace("Last commit to the version string %s" % (blame_rev
))
157 version_number_str
= 'cd %s; %s log %s..HEAD --oneline | wc -l | sed \'s/ //g\'' % (
158 self
.mono_package
.workspace
, git_bin
, blame_rev
)
159 self
.BUILD_NUMBER
= backtick(version_number_str
)[0]
160 trace("Calculating commit distance, %s" % (self
.BUILD_NUMBER
))
161 self
.FULL_VERSION
= self
.RELEASE_VERSION
+ "." + self
.BUILD_NUMBER
164 parts
= self
.RELEASE_VERSION
.split(".")
165 version_list
= (parts
+ ["0"] * (3 - len(parts
)))[:4]
166 for i
in range(1, 3):
167 version_list
[i
] = version_list
[i
].zfill(2)
168 self
.updateid
= "".join(version_list
)
169 self
.updateid
+= self
.BUILD_NUMBER
.replace(
170 ".", "").zfill(9 - len(self
.updateid
))
173 # creates and returns the path to a working directory containing:
174 # PKGROOT/ - this root will be bundled into the .pkg and extracted at /
175 # uninstallMono.sh - copied onto the DMG
176 # Info{_sdk}.plist - used by packagemaker to make the installer
177 # resources/ - other resources used by packagemaker for the installer
178 def setup_working_dir(self
):
179 def make_package_symlinks(root
):
180 os
.symlink(self
.prefix
, os
.path
.join(root
, "Versions", "Current"))
181 currentlink
= os
.path
.join(self
.MONO_ROOT
, "Versions", "Current")
184 ("include", "Headers"),
185 ("lib", "Libraries"),
187 (os
.path
.join("lib", "libmono-2.0.dylib"), "Mono")
189 for srcname
, destname
in links
:
190 src
= os
.path
.join(currentlink
, srcname
)
191 dest
= os
.path
.join(root
, destname
)
192 # If the symlink exists, we remove it so we can create a fresh
194 if os
.path
.exists(dest
):
196 os
.symlink(src
, dest
)
198 tmpdir
= tempfile
.mkdtemp()
199 monoroot
= os
.path
.join(tmpdir
, "PKGROOT", self
.MONO_ROOT
[1:])
200 versions
= os
.path
.join(monoroot
, "Versions")
201 os
.makedirs(versions
)
203 print "Setting up temporary package directory:", tmpdir
206 self
.packaging_dir
= os
.path
.join(self
.directory
, "packaging")
207 run_shell('rsync -aPq %s/* %s' % (self
.packaging_dir
, tmpdir
), False)
209 packages_list
= string
.join(
210 [pkg
.desc
for pkg
in self
.release_packages
.values()], "\\\n")
211 deps_list
= 'bockbuild (rev. %s)\\\n' % bockbuild
.bockbuild_rev
+ string
.join(
212 [pkg
.desc
for pkg
in self
.toolchain_packages
.values()], "\\\n")
215 '@@MONO_VERSION@@': self
.RELEASE_VERSION
,
216 '@@MONO_RELEASE@@': self
.BUILD_NUMBER
,
217 '@@MONO_VERSION_RELEASE@@': self
.RELEASE_VERSION
+ '_' + self
.BUILD_NUMBER
,
218 '@@MONO_CSDK_GUID@@': self
.MDK_GUID
,
219 '@@MONO_VERSION_RELEASE_INT@@': self
.updateid
,
220 '@@PACKAGES@@': packages_list
,
221 '@@DEP_PACKAGES@@': deps_list
223 for dirpath
, d
, files
in os
.walk(tmpdir
):
225 if not name
.startswith('.'):
226 replace_in_file(os
.path
.join(dirpath
, name
), parameter_map
)
228 make_package_symlinks(monoroot
)
230 # copy to package root
231 run_shell('rsync -aPq "%s"/* "%s/%s"' %
232 (bockbuild
.package_root
, versions
, self
.RELEASE_VERSION
), False)
236 def apply_blacklist(self
, working_dir
, blacklist_name
):
237 print "Applying blacklist script:", blacklist_name
238 blacklist
= os
.path
.join(self
.packaging_dir
, blacklist_name
)
239 root
= os
.path
.join(working_dir
, "PKGROOT", self
.prefix
[1:])
240 run_shell('%s "%s" > /dev/null' % (blacklist
, root
), print_cmd
=False)
242 def run_pkgbuild(self
, working_dir
, package_type
):
243 print 'Running pkgbuild & productbuild...',
244 info
= self
.package_info(package_type
)
245 output
= os
.path
.join(self
.directory
, info
["filename"])
246 identifier
= "com.xamarin.mono-" + info
["type"] + ".pkg"
247 resources_dir
= os
.path
.join(working_dir
, "resources")
248 distribution_xml
= os
.path
.join(resources_dir
, "distribution.xml")
250 old_cwd
= os
.getcwd()
251 os
.chdir(working_dir
)
252 pkgbuild
= "/usr/bin/pkgbuild"
253 pkgbuild_cmd
= ' '.join([pkgbuild
,
254 "--identifier " + identifier
,
255 "--root '%s/PKGROOT'" % working_dir
,
256 "--version '%s'" % self
.RELEASE_VERSION
,
257 "--install-location '/'",
258 "--scripts '%s'" % resources_dir
,
260 os
.path
.join(working_dir
, "mono.pkg")])
262 run_shell(pkgbuild_cmd
)
264 productbuild
= "/usr/bin/productbuild"
265 productbuild_cmd
= ' '.join([productbuild
,
266 "--resources %s" % resources_dir
,
267 "--distribution %s" % distribution_xml
,
268 "--package-path %s" % working_dir
,
272 run_shell(productbuild_cmd
)
274 assert_exists(output
)
279 def make_updateinfo(self
, working_dir
, guid
):
280 updateinfo
= os
.path
.join(
281 working_dir
, "PKGROOT", self
.prefix
[1:], "updateinfo")
282 with
open(updateinfo
, "w") as updateinfo
:
283 updateinfo
.write(guid
+ ' ' + self
.updateid
+ "\n")
285 def package_info(self
, pkg_type
):
286 arch
= self
.bockbuild
.cmd_options
.arch
288 if arch
== "darwin-32":
290 elif arch
== "darwin-64":
292 elif arch
== "darwin-universal":
293 arch_str
= "universal"
295 error ("Unknown architecture")
297 if self
.bockbuild
.cmd_options
.release_build
:
298 info
= (pkg_type
, self
.FULL_VERSION
, arch_str
)
300 info
= (pkg_type
, '%s-%s' % (git_shortid(self
.bockbuild
,
301 self
.mono_package
.workspace
), self
.FULL_VERSION
), arch_str
)
303 filename
= "MonoFramework-%s-%s.macos10.xamarin.%s.pkg" % info
309 def fix_line(self
, line
, matcher
):
310 def insert_install_root(matches
):
312 captures
= matches
.groupdict()
313 return 'target="%s"' % os
.path
.join(root
, "lib", captures
["lib"])
316 pattern
= r
'target="(?P<lib>.+\.dylib)"'
317 result
= re
.sub(pattern
, insert_install_root
, line
)
322 def fix_dllmap(self
, config
, matcher
):
323 handle
, temp
= tempfile
.mkstemp()
324 with
open(config
) as c
:
325 with
open(temp
, "w") as output
:
327 output
.write(self
.fix_line(line
, matcher
))
328 os
.rename(temp
, config
)
329 os
.system('chmod a+r %s' % config
)
331 def fix_gtksharp_configs(self
):
332 print 'Fixing GTK# configuration files...',
343 gac
= os
.path
.join(bockbuild
.package_root
, "lib", "mono", "gac")
344 confs
= [glob
.glob(os
.path
.join(gac
, x
, "*", "*.dll.config")) for x
in libs
]
345 for c
in itertools
.chain(*confs
):
347 self
.fix_dllmap(c
, lambda line
: "dllmap" in line
)
351 result
= " ".join(backtick("otool -L " + f
))
352 regex
= os
.path
.join(self
.MONO_ROOT
, "Versions", r
"(\d+\.\d+\.\d+)")
354 match
= re
.search(regex
, result
)
357 token
= match
.group(1)
359 if self
.RELEASE_VERSION
not in token
:
360 raise Exception("%s references Mono %s\n%s" % (f
, token
, text
))
362 def verify_binaries(self
):
363 bindir
= os
.path
.join(bockbuild
.package_root
, "bin")
364 for path
, dirs
, files
in os
.walk(bindir
):
366 f
= os
.path
.join(path
, name
)
367 file_type
= backtick('file "%s"' % f
)
368 if "Mach-O executable" in "".join(file_type
):
372 envscript
= '''#!/bin/sh
376 export DYLD_FALLBACK_LIBRARY_PATH="$INSTALLDIR/lib:/lib:/usr/lib"
377 export ACLOCAL_PATH="$INSTALLDIR/share/aclocal"
378 export CONFIG_SITE="$INSTALLDIR/$PROFNAME-config.site"
379 export MONO_GAC_PREFIX="$INSTALLDIR"
380 export MONO_ADDINS_REGISTRY="$ROOT/addinreg"
381 export MONO_INSTALL_PREFIX="$INSTALLDIR"
383 export PS1="\[\e[1;3m\][$PROFNAME] \w @ "
385 ''' % (self
.profile_name
, self
.staged_prefix
, self
.root
)
387 path
= os
.path
.join(self
.root
, self
.profile_name
+ '.sh')
389 with
open(path
, 'w') as f
:
392 os
.chmod(path
, os
.stat(path
).st_mode | stat
.S_IEXEC
)
394 subprocess
.call(['bash', '-c', path
])