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',
55 'pcl-reference-assemblies',
65 def attach (self
, bockbuild
):
67 DarwinProfile
.attach (self
, bockbuild
)
69 # quick disk space check (http://stackoverflow.com/questions/787776/)
70 s
= os
.statvfs(bockbuild
.root
)
71 free_space
= (s
.f_bavail
* s
.f_frsize
) / (1024 * 1024 * 1024) # in GB
74 error('Low disk space (less than 10GB), aborting')
76 # check for XQuartz installation (needed for libgdiplus)
77 if not os
.path
.exists('/opt/X11/include/X11/Xlib.h'):
79 'XQuartz is required to be installed (download from http://xquartz.macosforge.org/) ')
81 self
.MONO_ROOT
= "/Library/Frameworks/Mono.framework"
82 self
.BUILD_NUMBER
= "0"
83 self
.MDK_GUID
= "964ebddd-1ffe-47e7-8128-5ce17ffffb05"
85 system_mono_dir
= '/Library/Frameworks/Mono.framework/Versions/Current'
86 self
.env
.set('system_mono', os
.path
.join(
87 system_mono_dir
, 'bin', 'mono'))
88 self
.env
.set('system_mcs', os
.path
.join(system_mono_dir
, 'bin', 'mcs'))
90 self
.env
.set('system_mono_version', backtick(
91 '%s --version' % self
.env
.system_mono
)[0])
93 # config overrides for some programs to be functional while staged
95 self
.env
.set('GDK_PIXBUF_MODULE_FILE',
96 '%{staged_prefix}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache')
97 self
.env
.set('GDK_PIXBUF_MODULEDIR',
98 '%{staged_prefix}/lib/gdk-pixbuf-2.0/2.10.0/loaders')
99 self
.env
.set('PANGO_SYSCONFDIR', '%{staged_prefix}/etc')
100 self
.env
.set('PANGO_LIBDIR', '%{staged_prefix}/lib')
101 # self.env.set ('MONO_PATH', '%{staged_prefix}/lib/mono/4.0')
102 self
.debug_info
= ['gtk+', 'cairo', 'glib',
103 'pango', 'mono', 'llvm', 'libgdiplus']
104 self
.cache_host
= None
106 def setup_release(self
):
107 self
.mono_package
= self
.release_packages
['mono']
108 dest
= os
.path
.join(self
.bockbuild
.build_root
, self
.mono_package
.source_dir_name
)
109 self
.mono_package
.fetch(dest
)
112 verbose('Mono version: %s' % self
.mono_package
.version
)
113 self
.RELEASE_VERSION
= self
.mono_package
.version
114 self
.prefix
= os
.path
.join(
115 self
.MONO_ROOT
, "Versions", self
.RELEASE_VERSION
)
117 if os
.path
.exists(self
.prefix
):
118 error('Prefix %s exists, and may interfere with the staged build. Please remove and try again.' % self
.prefix
)
120 self
.calculate_updateid()
122 self
.mono_package
.custom_version_str
= self
.FULL_VERSION
123 trace(self
.package_info('MDK'))
125 self
.dont_optimize
= ['pixman']
127 for p
in self
.release_packages
.values():
128 if p
.name
in self
.dont_optimize
:
130 self
.gcc_flags
.extend(['-O2'])
132 # THIS IS THE MAIN METHOD FOR MAKING A PACKAGE
134 self
.fix_gtksharp_configs()
135 self
.verify_binaries()
137 working
= self
.setup_working_dir()
140 self
.apply_blacklist(working
, 'mdk_blacklist.sh')
141 self
.make_updateinfo(working
, self
.MDK_GUID
)
142 mdk_pkg
= self
.run_pkgbuild(working
, "MDK")
145 shutil
.rmtree(working
)
147 def calculate_updateid(self
):
148 # Create the updateid
150 git_bin
= self
.bockbuild
.git_bin
151 trace("cur path is %s and git is %s" % (pwd
, git_bin
))
152 blame_rev_str
= 'cd %s; %s blame configure.ac HEAD | grep AC_INIT | sed \'s/ .*//\' ' % (
153 self
.mono_package
.workspace
, git_bin
)
154 blame_rev
= backtick(blame_rev_str
)[0]
155 trace("Last commit to the version string %s" % (blame_rev
))
156 version_number_str
= 'cd %s; %s log %s..HEAD --oneline | wc -l | sed \'s/ //g\'' % (
157 self
.mono_package
.workspace
, git_bin
, blame_rev
)
158 self
.BUILD_NUMBER
= backtick(version_number_str
)[0]
159 trace("Calculating commit distance, %s" % (self
.BUILD_NUMBER
))
160 self
.FULL_VERSION
= self
.RELEASE_VERSION
+ "." + self
.BUILD_NUMBER
163 parts
= self
.RELEASE_VERSION
.split(".")
164 version_list
= (parts
+ ["0"] * (3 - len(parts
)))[:4]
165 for i
in range(1, 3):
166 version_list
[i
] = version_list
[i
].zfill(2)
167 self
.updateid
= "".join(version_list
)
168 self
.updateid
+= self
.BUILD_NUMBER
.replace(
169 ".", "").zfill(9 - len(self
.updateid
))
172 # creates and returns the path to a working directory containing:
173 # PKGROOT/ - this root will be bundled into the .pkg and extracted at /
174 # Info{_sdk}.plist - used by packagemaker to make the installer
175 # resources/ - other resources used by packagemaker for the installer
176 def setup_working_dir(self
):
177 def make_package_symlinks(root
):
178 os
.symlink(self
.prefix
, os
.path
.join(root
, "Versions", "Current"))
179 currentlink
= os
.path
.join(self
.MONO_ROOT
, "Versions", "Current")
182 ("include", "Headers"),
183 ("lib", "Libraries"),
185 (os
.path
.join("lib", "libmono-2.0.dylib"), "Mono")
187 for srcname
, destname
in links
:
188 src
= os
.path
.join(currentlink
, srcname
)
189 dest
= os
.path
.join(root
, destname
)
190 # If the symlink exists, we remove it so we can create a fresh
192 if os
.path
.exists(dest
):
194 os
.symlink(src
, dest
)
196 tmpdir
= tempfile
.mkdtemp()
197 monoroot
= os
.path
.join(tmpdir
, "PKGROOT", self
.MONO_ROOT
[1:])
198 versions
= os
.path
.join(monoroot
, "Versions")
199 os
.makedirs(versions
)
201 print "Setting up temporary package directory:", tmpdir
204 self
.packaging_dir
= os
.path
.join(self
.directory
, "packaging")
205 run_shell('rsync -aPq %s/* %s' % (self
.packaging_dir
, tmpdir
), False)
207 packages_list
= string
.join(
208 [pkg
.desc
for pkg
in self
.release_packages
.values()], "\\\n")
209 deps_list
= 'bockbuild (rev. %s)\\\n' % bockbuild
.bockbuild_rev
+ string
.join(
210 [pkg
.desc
for pkg
in self
.toolchain_packages
.values()], "\\\n")
213 '@@MONO_VERSION@@': self
.RELEASE_VERSION
,
214 '@@MONO_RELEASE@@': self
.BUILD_NUMBER
,
215 '@@MONO_VERSION_RELEASE@@': self
.RELEASE_VERSION
+ '_' + self
.BUILD_NUMBER
,
216 '@@MONO_CSDK_GUID@@': self
.MDK_GUID
,
217 '@@MONO_VERSION_RELEASE_INT@@': self
.updateid
,
218 '@@PACKAGES@@': packages_list
,
219 '@@DEP_PACKAGES@@': deps_list
221 for dirpath
, d
, files
in os
.walk(tmpdir
):
223 if not name
.startswith('.'):
224 replace_in_file(os
.path
.join(dirpath
, name
), parameter_map
)
226 make_package_symlinks(monoroot
)
228 # copy to package root
229 run_shell('rsync -aPq "%s"/* "%s/%s"' %
230 (bockbuild
.package_root
, versions
, self
.RELEASE_VERSION
), False)
234 def apply_blacklist(self
, working_dir
, blacklist_name
):
235 print "Applying blacklist script:", blacklist_name
236 blacklist
= os
.path
.join(self
.packaging_dir
, blacklist_name
)
237 root
= os
.path
.join(working_dir
, "PKGROOT", self
.prefix
[1:])
238 run_shell('%s "%s" > /dev/null' % (blacklist
, root
), print_cmd
=False)
240 def run_pkgbuild(self
, working_dir
, package_type
):
241 print 'Running pkgbuild & productbuild...',
242 info
= self
.package_info(package_type
)
243 output
= os
.path
.join(self
.directory
, info
["filename"])
244 identifier
= "com.xamarin.mono-" + info
["type"] + ".pkg"
245 resources_dir
= os
.path
.join(working_dir
, "resources")
246 distribution_xml
= os
.path
.join(resources_dir
, "distribution.xml")
248 old_cwd
= os
.getcwd()
249 os
.chdir(working_dir
)
250 pkgbuild
= "/usr/bin/pkgbuild"
251 pkgbuild_cmd
= ' '.join([pkgbuild
,
252 "--identifier " + identifier
,
253 "--root '%s/PKGROOT'" % working_dir
,
254 "--version '%s'" % self
.RELEASE_VERSION
,
255 "--install-location '/'",
256 "--scripts '%s'" % resources_dir
,
258 os
.path
.join(working_dir
, "mono.pkg")])
260 run_shell(pkgbuild_cmd
)
262 productbuild
= "/usr/bin/productbuild"
263 productbuild_cmd
= ' '.join([productbuild
,
264 "--resources %s" % resources_dir
,
265 "--distribution %s" % distribution_xml
,
266 "--package-path %s" % working_dir
,
270 run_shell(productbuild_cmd
)
272 assert_exists(output
)
277 def make_updateinfo(self
, working_dir
, guid
):
278 updateinfo
= os
.path
.join(
279 working_dir
, "PKGROOT", self
.prefix
[1:], "updateinfo")
280 with
open(updateinfo
, "w") as updateinfo
:
281 updateinfo
.write(guid
+ ' ' + self
.updateid
+ "\n")
282 version_file
= os
.path
.join(
283 working_dir
, "PKGROOT", self
.prefix
[1:], "VERSION")
284 with
open(version_file
, "w") as version_file
:
285 version_file
.write(self
.FULL_VERSION
+ "\n")
287 def package_info(self
, pkg_type
):
288 arch
= self
.bockbuild
.cmd_options
.arch
290 if arch
== "darwin-32":
292 elif arch
== "darwin-64":
294 elif arch
== "darwin-universal":
295 arch_str
= "universal"
297 error ("Unknown architecture")
299 if self
.bockbuild
.cmd_options
.release_build
:
300 info
= (pkg_type
, self
.FULL_VERSION
, arch_str
)
302 info
= (pkg_type
, '%s-%s' % (git_shortid(self
.bockbuild
,
303 self
.mono_package
.workspace
), self
.FULL_VERSION
), arch_str
)
305 filename
= "MonoFramework-%s-%s.macos10.xamarin.%s.pkg" % info
311 def fix_line(self
, line
, matcher
):
312 def insert_install_root(matches
):
314 captures
= matches
.groupdict()
315 return 'target="%s"' % os
.path
.join(root
, "lib", captures
["lib"])
318 pattern
= r
'target="(?P<lib>.+\.dylib)"'
319 result
= re
.sub(pattern
, insert_install_root
, line
)
324 def fix_dllmap(self
, config
, matcher
):
325 handle
, temp
= tempfile
.mkstemp()
326 with
open(config
) as c
:
327 with
open(temp
, "w") as output
:
329 output
.write(self
.fix_line(line
, matcher
))
330 os
.rename(temp
, config
)
331 os
.system('chmod a+r %s' % config
)
333 def fix_gtksharp_configs(self
):
334 print 'Fixing GTK# configuration files...',
345 gac
= os
.path
.join(bockbuild
.package_root
, "lib", "mono", "gac")
346 confs
= [glob
.glob(os
.path
.join(gac
, x
, "*", "*.dll.config")) for x
in libs
]
347 for c
in itertools
.chain(*confs
):
349 self
.fix_dllmap(c
, lambda line
: "dllmap" in line
)
353 result
= " ".join(backtick("otool -L " + f
))
354 regex
= os
.path
.join(self
.MONO_ROOT
, "Versions", r
"(\d+\.\d+\.\d+)")
356 match
= re
.search(regex
, result
)
359 token
= match
.group(1)
361 if self
.RELEASE_VERSION
not in token
:
362 raise Exception("%s references Mono %s\n%s" % (f
, token
, text
))
364 def verify_binaries(self
):
365 bindir
= os
.path
.join(bockbuild
.package_root
, "bin")
366 for path
, dirs
, files
in os
.walk(bindir
):
368 f
= os
.path
.join(path
, name
)
369 file_type
= backtick('file "%s"' % f
)
370 if "Mach-O executable" in "".join(file_type
):
374 envscript
= '''#!/bin/sh
378 export DYLD_FALLBACK_LIBRARY_PATH="$INSTALLDIR/lib:/lib:/usr/lib"
379 export ACLOCAL_PATH="$INSTALLDIR/share/aclocal"
380 export CONFIG_SITE="$INSTALLDIR/$PROFNAME-config.site"
381 export MONO_GAC_PREFIX="$INSTALLDIR"
382 export MONO_ADDINS_REGISTRY="$ROOT/addinreg"
383 export MONO_INSTALL_PREFIX="$INSTALLDIR"
385 export PS1="\[\e[1;3m\][$PROFNAME] \w @ "
387 ''' % (self
.profile_name
, self
.staged_prefix
, self
.root
)
389 path
= os
.path
.join(self
.root
, self
.profile_name
+ '.sh')
391 with
open(path
, 'w') as f
:
394 os
.chmod(path
, os
.stat(path
).st_mode | stat
.S_IEXEC
)
396 subprocess
.call(['bash', '-c', path
])