Permalink
Browse files

Moved the OSX package generation to SCons (#30)

  • Loading branch information...
1 parent b41e038 commit d580d3d3edb535a8c26acc91803909c9c78fe9d3 @ereOn ereOn committed Apr 18, 2015
View
@@ -20,3 +20,6 @@
# Vagrant
.vagrant
+
+# Package files
+*.pkg
View
@@ -59,3 +59,11 @@ You will need Microsoft Visual Studio 2013 to compile freelan. All projects come
The root directory also contains a solution file (`.sln`) that references all the sub-projects.
The resulting binaries will be located in the [install](install) directory.
+
+### Mac OSX
+
+On Mac OSX, an additional SCons target exists to build the freelan installation package:
+
+> scons package
+
+The package will be generated at the root of the repository.
View
@@ -57,24 +57,25 @@ for x in Glob('apps/*'):
samples = []
-for x in Glob('samples/*'):
- libname = os.path.basename(str(x))
+if env.mode != 'retail':
+ for x in Glob('samples/*'):
+ libname = os.path.basename(str(x))
- if not sys.platform.startswith('linux'):
- if libname in 'netlinkplus':
- continue
+ if not sys.platform.startswith('linux'):
+ if libname in 'netlinkplus':
+ continue
- for y in x.glob('*'):
- sconscript_path = y.File('SConscript')
+ for y in x.glob('*'):
+ sconscript_path = y.File('SConscript')
- if sconscript_path.exists():
- name = 'sample_%s_%s' % (libname, os.path.basename(str(y)))
- sample = SConscript(sconscript_path, exports='env dirs name')
- samples.extend(sample)
+ if sconscript_path.exists():
+ name = 'sample_%s_%s' % (libname, os.path.basename(str(y)))
+ sample = SConscript(sconscript_path, exports='env dirs name')
+ samples.extend(sample)
- if env.debug:
- samples.extend(env.SymLink(y.File('%sd' % os.path.basename(str(y))).srcnode(), sample))
- else:
- samples.extend(env.SymLink(y.File(os.path.basename(str(y))).srcnode(), sample))
+ if env.mode == 'release':
+ samples.extend(env.SymLink(y.File('%sd' % os.path.basename(str(y))).srcnode(), sample))
+ else:
+ samples.extend(env.SymLink(y.File(os.path.basename(str(y))).srcnode(), sample))
Return('libraries includes apps samples configurations')
View
@@ -40,12 +40,11 @@ class FreelanEnvironment(Environment):
A freelan specific environment class.
"""
- def __init__(self, debug, prefix, **kwargs):
+ def __init__(self, mode, prefix, **kwargs):
"""
Initialize the environment.
- :param debug: A boolean value that indicates whether to set debug flags
- in the environment.
+ :param mode: The compilation mode.
:param prefix: The installation prefix.
"""
super(FreelanEnvironment, self).__init__(**kwargs)
@@ -71,7 +70,7 @@ class FreelanEnvironment(Environment):
if flag in os.environ:
self[flag] = Split(os.environ[flag])
- self.debug = debug
+ self.mode = mode
self.prefix = prefix
if os.path.basename(self['CXX']) == 'clang++':
@@ -98,7 +97,7 @@ class FreelanEnvironment(Environment):
self.Append(CXXFLAGS=['--stdlib=libc++'])
self.Append(LDFLAGS=['--stdlib=libc++'])
- if self.debug:
+ if self.mode == 'debug':
self.Append(CXXFLAGS=['-g'])
self.Append(CXXFLAGS='-DFREELAN_DEBUG=1')
else:
@@ -151,20 +150,29 @@ mode = GetOption('mode')
prefix = os.path.abspath(GetOption('prefix'))
if mode in ('all', 'release'):
- env = FreelanEnvironment(debug=False, prefix=prefix)
- libraries, includes, apps, samples, configurations = SConscript('SConscript', exports='env', variant_dir=os.path.join('build', 'release'))
+ env = FreelanEnvironment(mode='release', prefix=prefix)
+ libraries, includes, apps, samples, configurations = SConscript('SConscript', exports='env', variant_dir=os.path.join('build', env.mode))
install = env.Install(os.path.join(prefix, 'bin'), apps)
install.extend(env.Install(os.path.join(prefix, 'etc', 'freelan'), configurations))
+
Alias('install', install)
Alias('apps', apps)
Alias('samples', samples)
Alias('all', install + apps + samples)
if mode in ('all', 'debug'):
- env = FreelanEnvironment(debug=True, prefix=prefix)
- libraries, includes, apps, samples, configurations = SConscript('SConscript', exports='env', variant_dir=os.path.join('build', 'debug'))
+ env = FreelanEnvironment(mode='debug', prefix=prefix)
+ libraries, includes, apps, samples, configurations = SConscript('SConscript', exports='env', variant_dir=os.path.join('build', env.mode))
Alias('apps', apps)
Alias('samples', samples)
Alias('all', apps + samples)
+if sys.platform.startswith('darwin'):
+ retail_prefix = '/usr/local'
+ env = FreelanEnvironment(mode='retail', prefix=retail_prefix)
+ libraries, includes, apps, samples, configurations = SConscript('SConscript', exports='env', variant_dir=os.path.join('build', env.mode))
+ package = SConscript('packaging/osx/SConscript', exports='env apps configurations retail_prefix')
+ install_package = env.Install('.', package)
+ Alias('package', install_package)
+
Default('install')
View
@@ -72,6 +72,10 @@ def version(self):
return self._version
@property
+ def version_str(self):
+ return '%s.%s' % (self.version.major, self.version.minor)
+
+ @property
def date(self):
if self._date is None:
self._date = datetime.date.today().strftime('%a %d %b %Y')
@@ -125,6 +129,7 @@ def register_into(self, env):
action=self.action,
emitter=self.emitter,
)})
+ env.defines = self
def generate_defines(self, target):
"""
@@ -1,2 +1,3 @@
-*.pkg
-org.freelan.freelan
+distribution.xml
+root/
+resources/conclusion.html
@@ -1,23 +0,0 @@
-PRODUCT_NAME=freelan
-IDENTIFIER=org.freelan.freelan
-VERSION=2.0
-DAEMON_PACKAGE=${IDENTIFIER}.pkg
-FINAL_PACKAGE=${PRODUCT_NAME}_${VERSION}.pkg
-
-default: package
-
-clean:
- rm -rf ${IDENTIFIER}
- rm -f ${DAEMON_PACKAGE}
- rm -f ${FINAL_PACKAGE}
-
-package: clean
- mkdir -p ${IDENTIFIER}
- mkdir -p ${IDENTIFIER}/usr/local
- mkdir -p ${IDENTIFIER}/usr/local/share/freelan
- mkdir -p ${IDENTIFIER}/Library/LaunchDaemons
- cp -r ../../install/* ${IDENTIFIER}/usr/local/
- cp org.freelan.freelan.plist ${IDENTIFIER}/Library/LaunchDaemons/
- cp uninstall.sh ${IDENTIFIER}/usr/local/share/freelan/
- pkgbuild --root ${IDENTIFIER} --identifier ${IDENTIFIER} --version ${VERSION} --ownership recommended --scripts scripts ${DAEMON_PACKAGE}
- productbuild --distribution distribution.xml --resources resources --package-path . --version ${VERSION} ${FINAL_PACKAGE}
@@ -1,3 +1,5 @@
# Mac OS X Installer
-To build the Mac OS X package, just type "make".
+To build the Mac OS X package, just type "scons -u .".
+
+You can also build it from the repository root by typing "scons package".
@@ -0,0 +1,104 @@
+import os
+import pkgbuild
+import productbuild
+import plist
+import generate_script
+import template
+
+
+def relative(path):
+ return path.lstrip('/')
+
+
+Import('env apps configurations retail_prefix')
+
+env = env.Clone()
+
+for module in [pkgbuild, productbuild, plist, generate_script, template]:
+ module.generate(env)
+
+root = env.Dir('root')
+scripts = env.Dir('scripts')
+options = {
+ 'identifier': 'org.freelan.freelan',
+ 'version': env.defines.version_str,
+ 'ownership': 'recommended',
+}
+resources = env.Dir('resources')
+distribution_template = env.File('distribution.xml.in')
+conclusion_template = resources.File('conclusion.html.in')
+
+bin_path = os.path.join(retail_prefix, 'bin')
+etc_freelan_path = os.path.join(retail_prefix, 'etc/freelan')
+share_freelan_path = os.path.join(retail_prefix, 'share/freelan')
+uninstall_script = os.path.join(share_freelan_path, 'uninstall.sh')
+launch_daemon_script = os.path.join(
+ '/Library/LaunchDaemons',
+ options['identifier'] + '.plist',
+)
+
+uninstall_script_source = env.Value([
+ '/bin/launchctl unload ' + launch_daemon_script,
+ 'rm -f ' + launch_daemon_script,
+ 'rm -f ' + os.path.join(bin_path, apps[0].name),
+ 'rm -rf ' + etc_freelan_path,
+])
+launch_daemon_script_source = env.Value({
+ 'Label': options['identifier'],
+ 'ProgramArguments': [
+ os.path.join(bin_path, apps[0].name),
+ '-c',
+ os.path.join(etc_freelan_path, configurations[0].name),
+ '-f',
+ ],
+ 'RunAtLoad': True,
+ 'KeepAlive': True,
+})
+
+env.Install(
+ root.Dir(relative(bin_path)),
+ apps,
+)
+env.Install(
+ root.Dir(relative(etc_freelan_path)),
+ configurations,
+)
+env.GenerateScript(
+ root.File(relative(uninstall_script)),
+ uninstall_script_source,
+)
+env.Plist(
+ root.File(relative(launch_daemon_script)),
+ launch_daemon_script_source,
+)
+
+package = env.PkgBuild(
+ target=options['identifier'] + '.pkg',
+ source=root,
+ PKGBUILD_OPTIONS=env.Value(options),
+ PKGBUILD_SCRIPTS=scripts,
+)
+distribution_file = env.Template(
+ source=distribution_template,
+ TEMPLATE_DICT=env.Value({'version': env.defines.version_str}),
+)
+conclusion_file = env.Template(
+ source=conclusion_template,
+ TEMPLATE_DICT=env.Value({
+ 'configuration_file': os.path.join(
+ etc_freelan_path,
+ configurations[0].name,
+ )
+ }),
+)
+final_package = env.ProductBuild(
+ target='freelan_{version}.pkg'.format(version=env.defines.version_str),
+ source=distribution_file,
+ PRODUCTBUILD_OPTIONS=env.Value({
+ 'version': env.defines.version_str,
+ }),
+ PRODUCTBUILD_RESOURCES=resources,
+ PRODUCTBUILD_PACKAGE_PATH=[env.Dir('.')],
+)
+
+Return('final_package')
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<installer-gui-script minSpecVersion="1">
- <title>freelan 1.1</title>
+ <title>FreeLAN {version}</title>
<organization>org.freelan</organization>
<domains enable_localSystem="true"/>
<options customize="never" require-scripts="true" rootVolumeOnly="true" />
@@ -18,7 +18,7 @@
</choices-outline>
<!-- Define each choice above -->
- <choice id="org.freelan.freelan" visible="false" title="freelan" description="The freelan daemon" start_selected="true">
+ <choice id="org.freelan.freelan" visible="false" title="FreeLAN" description="The FreeLAN binary" start_selected="true">
<pkg-ref id="org.freelan.freelan"/>
</choice>
</installer-gui-script>
@@ -0,0 +1,36 @@
+"""A SCons builder for plist files"""
+
+
+def generate_script_emitter(target, source, env):
+ env.Depends(target, env.Value(env['GENERATE_SCRIPT_TEMPLATE']))
+
+ return (target, source)
+
+
+def generate_script_action(target, source, env):
+ template = env['GENERATE_SCRIPT_TEMPLATE']
+
+ for targ in target:
+ with open(targ.abspath, 'w') as targf:
+ targf.write(
+ template.format(
+ commands='\n'.join(source[0].value),
+ ),
+ )
+
+
+def generate(env):
+ env.Append(GENERATE_SCRIPT_TEMPLATE="""#!/bin/sh
+
+{commands}
+""")
+
+ import SCons.Builder
+
+ generate_script_builder = SCons.Builder.Builder(
+ action=generate_script_action,
+ emitter=generate_script_emitter,
+ suffix='.sh',
+ )
+
+ env.Append(BUILDERS={'GenerateScript': generate_script_builder})
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>Label</key>
- <string>org.freelan.freelan</string>
- <key>ProgramArguments</key>
- <array>
- <string>/usr/local/bin/freelan</string>
- <string>-c</string>
- <string>/usr/local/etc/freelan/freelan.cfg</string>
- <string>-f</string>
- </array>
- <key>RunAtLoad</key><true/>
- <key>KeepAlive</key><true/>
-</dict>
-</plist>
Oops, something went wrong.

0 comments on commit d580d3d

Please sign in to comment.