[banshee] [build] big reorg of the bundle builder



commit f7ee543a354951fe5ddd442bf91c7685385804c3
Author: Aaron Bockover <abockover novell com>
Date:   Thu Jan 7 13:43:48 2010 -0500

    [build] big reorg of the bundle builder
    
    Moved a lot of code into proper classes and modules, redesigned
    the package format to just be proper python classes that extend
    or instantiate the new base Package class which does all the
    build work. Everything is much simpler and more extensible now.

 bootstrap-bundle                                   |    6 +-
 build/bundle/{ => bockbuild}/build.py              |  138 +++++----------
 build/bundle/bockbuild/darwinprofile.py            |   22 +++
 build/bundle/bockbuild/environment.py              |   58 ++++++
 build/bundle/bockbuild/package.py                  |  183 ++++++++++++++++++++
 build/bundle/bockbuild/profile.py                  |   38 ++++
 build/bundle/bockbuild/unixprofile.py              |   31 ++++
 build/bundle/bockbuild/util.py                     |   83 +++++++++
 build/bundle/packages.py                           |   83 +++++++++
 build/bundle/packages/atk.py                       |   10 +-
 build/bundle/packages/autoconf.py                  |    8 +-
 build/bundle/packages/automake.py                  |    8 +-
 build/bundle/packages/cairo.py                     |   47 +++---
 build/bundle/packages/flac.py                      |   26 +--
 build/bundle/packages/fontconfig.py                |   13 +-
 build/bundle/packages/freetype.py                  |   14 +--
 build/bundle/packages/gconf-dummy.py               |   19 +-
 build/bundle/packages/gettext.py                   |   16 +--
 build/bundle/packages/glib.py                      |   73 ++++----
 build/bundle/packages/gst-plugins-bad.py           |   27 +--
 build/bundle/packages/gst-plugins-base.py          |   46 ++---
 build/bundle/packages/gst-plugins-good.py          |   50 +++---
 build/bundle/packages/gst-plugins-ugly.py          |   30 ++--
 build/bundle/packages/gstreamer.py                 |   15 +--
 build/bundle/packages/gtk+.py                      |   56 +++----
 build/bundle/packages/gtk-sharp.py                 |   55 +++---
 build/bundle/packages/hicolor-icon-theme.py        |    8 +-
 build/bundle/packages/icon-naming-utils.py         |    8 +-
 build/bundle/packages/ige-mac-integration-sharp.py |   10 +-
 build/bundle/packages/ige-mac-integration.py       |    8 +-
 build/bundle/packages/intltool.py                  |   10 +-
 build/bundle/packages/libglade.py                  |   10 +-
 build/bundle/packages/libjpeg.py                   |   13 +-
 build/bundle/packages/libogg.py                    |    8 +-
 build/bundle/packages/liboil.py                    |   18 +-
 build/bundle/packages/libpng.py                    |   14 +--
 build/bundle/packages/libproxy.py                  |   10 +-
 build/bundle/packages/librsvg.py                   |   10 +-
 build/bundle/packages/libsoup.py                   |   21 +--
 build/bundle/packages/libtheora.py                 |    8 +-
 build/bundle/packages/libtool.py                   |    8 +-
 build/bundle/packages/libvorbis.py                 |    8 +-
 build/bundle/packages/libxml2.py                   |   13 +-
 build/bundle/packages/mono-addins.py               |   19 +--
 build/bundle/packages/mono.py                      |   46 ++---
 build/bundle/packages/ndesk-dbus-glib.py           |   10 +-
 build/bundle/packages/ndesk-dbus.py                |   10 +-
 build/bundle/packages/pango.py                     |   26 ++--
 build/bundle/packages/pixman.py                    |    8 +-
 build/bundle/packages/pkg-config.py                |   10 +-
 build/bundle/packages/speex.py                     |    8 +-
 build/bundle/packages/sqlite.py                    |   10 +-
 build/bundle/packages/taglib-sharp.py              |   16 +--
 build/bundle/packages/taglib.py                    |   10 +-
 build/bundle/packages/tango-icon-theme.py          |   15 +--
 build/bundle/packages/wavpack.py                   |   10 +-
 build/bundle/profile.darwin.py                     |   11 ++
 build/bundle/profile.linux.py                      |   98 ++---------
 build/bundle/profile.osx.py                        |  101 -----------
 59 files changed, 887 insertions(+), 861 deletions(-)
---
diff --git a/bootstrap-bundle b/bootstrap-bundle
index 88f9b4c..d3ad00f 100755
--- a/bootstrap-bundle
+++ b/bootstrap-bundle
@@ -7,7 +7,7 @@ profile_name="$1"
 if test -z "$profile_name"; then
 	case "$(uname)" in
 		Linux) profile_name=linux ;;
-		Darwin) profile_name=osx ;;
+		Darwin) profile_name=darwin ;;
 		*)
 			echo "Unsupported system type: $(uname)"
 			exit 1
@@ -23,8 +23,8 @@ if ! test -f "build/bundle/$profile"; then
 fi
 
 pushd build/bundle &>/dev/null
-./build.py -v $profile
-./build.py -e $profile > $profile_name.env
+./$profile -bv
+./$profile -e > $profile_name.env
 source $profile_name.env
 popd &>/dev/null
 
diff --git a/build/bundle/bockbuild/__init__.py b/build/bundle/bockbuild/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/build/bundle/build.py b/build/bundle/bockbuild/build.py
similarity index 64%
rename from build/bundle/build.py
rename to build/bundle/bockbuild/build.py
index 6284535..a1952a7 100755
--- a/build/bundle/build.py
+++ b/build/bundle/bockbuild/build.py
@@ -6,26 +6,26 @@ import re
 import glob
 import shutil
 import urllib
-import subprocess
+from util import *
 from optparse import OptionParser
 
 def build_package (profile, (package, vars)):
 	package_dir = os.path.dirname (package['_path'])
-	package_dest_dir = os.path.join (profile['build_root'],
+	package_dest_dir = os.path.join (profile.build_root,
 		'%s-%s' % (package['name'], package['version']))
 	package_build_dir = os.path.join (package_dest_dir, '_build')
-	build_success_file = os.path.join (profile['build_root'],
+	build_success_file = os.path.join (profile.build_root,
 		'%s-%s.success' % (package['name'], package['version']))
 
 	if os.path.exists (build_success_file):
 		print 'Skipping %s - already built' % package['name']
 		return
 
-	print 'Building %s on %s (%s CPU)' % (package['name'], profile['host'], profile['cpu_count'])
+	print 'Building %s on %s (%s CPU)' % (package['name'], profile.host, profile.cpu_count)
 
 	# Set up the directories
-	if not os.path.exists (profile['build_root']) or not os.path.isdir (profile['build_root']):
-		os.makedirs (profile['build_root'], 0755)
+	if not os.path.exists (profile.build_root) or not os.path.isdir (profile.build_root):
+		os.makedirs (profile.build_root, 0755)
 
 	shutil.rmtree (package_build_dir, ignore_errors = True)
 	os.makedirs (package_build_dir)
@@ -36,7 +36,7 @@ def build_package (profile, (package, vars)):
 	log (0, 'Retrieving sources')
 	local_sources = []
 	for source in package['sources']:
-		source = expand_macros (source, vars)
+		source = legacy_expand_macros (source, vars)
 		local_source = os.path.join (package_dir, source)
 		local_source_file = os.path.basename (local_source)
 		local_dest_file = os.path.join (package_dest_dir, local_source_file)
@@ -56,19 +56,19 @@ def build_package (profile, (package, vars)):
 	
 	os.chdir (package_build_dir)
 
-	for phase in profile['run_phases']:
+	for phase in profile.run_phases:
 		log (0, '%sing %s' % (phase.capitalize (), package['name']))
 		for step in package[phase]:
 			if hasattr (step, '__call__'):
 				log (1, '<py call: %s>' % step.__name__)
 				step (package)
 				continue
-			step = expand_macros (step, package)
+			step = legacy_expand_macros (step, package)
 			log (1, step)
 			if step.startswith ('cd '):
 				os.chdir (step[3:])
 			else:
-				if not profile['verbose']:
+				if not profile.verbose:
 					step = '( %s ) &>/dev/null' % step
 				run_shell (step)
 
@@ -76,12 +76,12 @@ def build_package (profile, (package, vars)):
 
 def load_package_defaults (profile, package):
 	# path macros
-	package['_build_root'] = os.path.join (profile['build_root'], '_install')
+	package['_build_root'] = os.path.join (profile.build_root, '_install')
 	package['_prefix'] = package['_build_root']
 
 	# tool macros
 	package['__configure'] = './configure --prefix=%{_prefix}'
-	package['__make'] = 'make -j%s' % profile['cpu_count']
+	package['__make'] = 'make -j%s' % profile.cpu_count
 	package['__makeinstall'] = 'make install'
 
 	# install default sections if they are missing
@@ -104,7 +104,7 @@ def parse_package (profile, package):
 		vars[k] = v
 
 	# now process the package tree and substitute variables
-	package = expand_macros (package, vars, runtime = False)
+	package = legacy_expand_macros (package, vars, runtime = False)
 
 	for req in ['name', 'version', 'sources', 'prep', 'build', 'install']:
 		if not req in package:
@@ -115,7 +115,7 @@ def parse_package (profile, package):
 
 	return package, vars
 
-def expand_macros (node, vars, runtime = True):
+def legacy_expand_macros (node, vars, runtime = True):
 	macro_type = '%'
 	if runtime:
 		macro_type = '@'
@@ -136,10 +136,10 @@ def expand_macros (node, vars, runtime = True):
 
 	if isinstance (node, dict):
 		for k, v in node.iteritems ():
-			node[k] = expand_macros (v, vars, runtime)
+			node[k] = legacy_expand_macros (v, vars, runtime)
 	elif isinstance (node, (list, tuple)):
 		for i, v in enumerate (node):
-			node[i] = expand_macros (v, vars, runtime)
+			node[i] = legacy_expand_macros (v, vars, runtime)
 	elif isinstance (node, str):
 		orig_node = node
 		iters = 0
@@ -155,41 +155,6 @@ def expand_macros (node, vars, runtime = True):
 	return node
 
 #--------------------------------------
-# Utility Functions
-#--------------------------------------
-
-def run_shell (cmd):
-	proc = subprocess.Popen (cmd, shell = True)
-	exit_code = os.waitpid (proc.pid, 0)[1]
-	if not exit_code == 0:
-		print
-		sys.exit ('ERROR: command exited with exit code %s: %s' % (exit_code, cmd))
-
-def backtick (cmd):
-	lines = []
-	for line in os.popen (cmd).readlines ():
-		lines.append (line.rstrip ('\r\n'))
-	return lines
-
-def get_host ():
-	search_paths = ['/usr/share', '/usr/local/share']
-	am_config_guess = []
-	for path in search_paths:
-		am_config_guess.extend (glob.glob (os.path.join (
-			path, os.path.join ('automake*', 'config.guess'))))
-	for config_guess in am_config_guess:
-		config_sub = os.path.join (os.path.dirname (config_guess), 'config.sub')
-		if os.access (config_guess, os.X_OK) and os.access (config_sub, os.X_OK):
-			return backtick ('%s %s' % (config_sub, backtick (config_guess)[0]))[0]
-	return 'python-%s' % os.name
-
-def get_cpu_count ():
-	try:
-		return os.sysconf ('SC_NPROCESSORS_CONF')
-	except:
-		return 1
-
-#--------------------------------------
 # Logging
 #--------------------------------------
 
@@ -205,10 +170,13 @@ def log (level, message):
 # Main Program
 #--------------------------------------
 
-if __name__ == '__main__':
+def main (profile):
 	default_run_phases = ['prep', 'build', 'install']
 
-	parser = OptionParser (usage = 'usage: %prog [options] profile-path [package_names...]')
+	parser = OptionParser (usage = 'usage: %prog [options] [package_names...]')
+	parser.add_option ('-b', '--build',
+		action = 'store_true', dest = 'do_build', default = False,
+		help = 'build the profile')
 	parser.add_option ('-v', '--verbose',
 		action = 'store_true', dest = 'verbose', default = False,
 		help = 'show all build output (e.g. configure, make)')
@@ -226,65 +194,47 @@ if __name__ == '__main__':
 		help = 'Dump the profile environment as a shell-sourceable list of exports ')
 	options, args = parser.parse_args ()
 	
-	if args == []:
-		parser.print_help ()
-		sys.exit (1)
-
-	profile_path = args[0]
-	packages_to_build = args[1:]
-
-	if not os.path.exists (profile_path):
-		sys.exit ('Profile %s does not exist.' % profile_path)
-
-	try:
-		exec open (profile_path).read ()
-	except Exception, e:
-		sys.exit ('Cannot load profile %s: %s' % (profile_path, e))
-
-	profile_vars = {}
-	for d in [profile, profile['environ']]:
-		for k, v in d.iteritems ():
-			profile_vars[k] = v
-
-	profile = expand_macros (profile, profile_vars, False)
-	profile.setdefault ('cpu_count', get_cpu_count ())
-	profile.setdefault ('host', get_host ())
-	profile.setdefault ('verbose', options.verbose)
-	profile.setdefault ('run_phases', default_run_phases)
+	packages_to_build = args
+	profile.verbose = options.verbose
+	profile.run_phases = default_run_phases
 
 	if options.dump_environment:
-		for k, v in profile['environ'].iteritems ():
-			print 'export %s="%s"' % (k, v)
+		profile.env.compile ()
+		profile.env.dump ()
 		sys.exit (0)
 
+	if not options.do_build:
+		parser.print_help ()
+		sys.exit (1)
+
 	if not options.include_run_phases == []:
-		profile['run_phases'] = options.include_run_phases
+		profile.run_phases = options.include_run_phases
 	for exclude_phase in options.exclude_run_phases:
-		profile['run_phases'].remove (exclude_phase)
+		profile.run_phases.remove (exclude_phase)
 	if options.only_sources:
-		profile['run_phases'] = []
+		profile.run_phases = []
 
-	for phase_set in [profile['run_phases'],
+	for phase_set in [profile.run_phases,
 		options.include_run_phases, options.exclude_run_phases]:
 		for phase in phase_set:
 			if phase not in default_run_phases:
 				sys.exit ('Invalid run phase \'%s\'' % phase)
 
-	log (0, 'Loaded profile \'%s\' (%s)' % (profile['name'], profile['host']))
-	for phase in profile['run_phases']:
+	log (0, 'Loaded profile \'%s\' (%s)' % (profile.name, profile.host))
+	for phase in profile.run_phases:
 		log (1, 'Phase \'%s\' will run' % phase)
 
-	if 'environ' in profile:
-		log (0, 'Setting environment variables')
-		for k, v in profile['environ'].iteritems ():
-			os.environ[k] = v
-			log (1, '%s = %s' % (k, os.getenv (k)))
+	profile.env.compile ()
+	profile.env.export ()
+	log (0, 'Setting environment variables')
+	for k in profile.env.get_names ():
+		log (1, '%s = %s' % (k, os.getenv (k)))
 
 	pwd = os.getcwd ()
-	for path in profile['packages']:
+	for path in profile.packages:
 		os.chdir (pwd)
-		path = os.path.join (os.path.dirname (profile_path), path)
-		exec open (path).read ()
+		path = os.path.join (os.path.dirname (sys.argv[0]), path)
+		exec compile (open (path).read (), path, 'exec')
 		if not packages_to_build == [] and package['name'] not in packages_to_build:
 			continue
 		package['_path'] = path
diff --git a/build/bundle/bockbuild/darwinprofile.py b/build/bundle/bockbuild/darwinprofile.py
new file mode 100644
index 0000000..e3db9e7
--- /dev/null
+++ b/build/bundle/bockbuild/darwinprofile.py
@@ -0,0 +1,22 @@
+import os
+from unixprofile import UnixProfile
+
+class DarwinProfile (UnixProfile):
+	def __init__ (self):
+		UnixProfile.__init__ (self)
+		
+		self.name = 'darwin'
+		self.mac_sdk_path = '/Developer/SDKs/MacOSX10.5.sdk'
+		
+		if not os.path.isdir (self.mac_sdk_path):
+			raise IOError ('Mac OS X SDK does not exist: %s' \
+				% self.mac_sdk_path)
+
+		self.gcc_flags.extend ([
+			'-D_XOPEN_SOURCE',
+			'-isysroot %{mac_sdk_path}',
+			'-mmacosx-version-min=10.5'
+		])
+
+		self.env.set ('CC',  'gcc-4.2')
+		self.env.set ('CXX', 'g++-4.2')
diff --git a/build/bundle/bockbuild/environment.py b/build/bundle/bockbuild/environment.py
new file mode 100644
index 0000000..307deea
--- /dev/null
+++ b/build/bundle/bockbuild/environment.py
@@ -0,0 +1,58 @@
+import os
+from util import *
+from collections import deque
+
+class EnvironmentItem:
+	def __init__ (self, name, joinchar, values):
+		self.name = name
+		self.joinchar = joinchar
+		self.values = values
+	
+	def __str__ (self):
+		return self.joinchar.join (self.values)
+
+class Environment:
+	def __init__ (self, profile):
+		self._profile = profile
+
+	def set (self, *argv):
+		args = deque (argv)
+		name = args.popleft ()
+		joinchar = args.popleft ()
+		if len (args) == 0:
+			values = list (self.iter_flatten (joinchar))
+			joinchar = ''
+		else:
+			values = list (self.iter_flatten (list (args)))
+	
+		self.__dict__[name] = EnvironmentItem (name, joinchar, values)
+		return self.__dict__[name]
+
+	def compile (self):
+		expand_macros (self, self._profile)
+
+	def dump (self):
+		for k in self.get_names ():
+			print 'export %s="%s"' % (k, self.__dict__[k])
+
+	def export (self):
+		for k in self.get_names ():
+			os.environ[k] = str (self.__dict__[k])
+
+	def get_names (self):
+		for k in self.__dict__.keys ():
+			if not k.startswith ('_'):
+				yield k
+
+	def iter_flatten (self, iterable):
+		if not isinstance (iterable, (list, tuple)):
+			yield iterable
+			return
+		it = iter (iterable)
+		for e in it:
+			if isinstance (e, (list, tuple)):
+				for f in self.iter_flatten (e):
+					yield f
+			else:
+				yield e
+
diff --git a/build/bundle/bockbuild/package.py b/build/bundle/bockbuild/package.py
new file mode 100644
index 0000000..c43b54a
--- /dev/null
+++ b/build/bundle/bockbuild/package.py
@@ -0,0 +1,183 @@
+import os
+import sys
+import shutil
+import urllib
+from util import *
+
+class Package:
+	def __init__ (self, name, version, configure_flags = None, sources = None, source_dir_name = None, override_properties = None):
+		Package.last_instance = self
+		
+		self.name = name
+		self.version = version
+		self.configure_flags = configure_flags
+
+		self.sources = sources
+		if self.sources == None \
+			and not self.__class__.default_sources == None:
+			self.sources = list (self.__class__.default_sources)
+
+		self.source_dir_name = source_dir_name
+		if self.source_dir_name == None:
+			self.source_dir_name = '%{name}-%{version}'
+
+		self.prefix = os.path.join (Package.profile.build_root, '_install')
+		self.configure = './configure --prefix=%{prefix}'
+		self.make = 'make -j%s' % Package.profile.cpu_count
+		self.makeinstall = 'make install'
+
+		if not override_properties == None:
+			for k, v in override_properties.iteritems ():
+				self.__dict__[k] = v
+
+	def _fetch_sources (self, package_dir, package_dest_dir):
+		if self.sources == None:
+			return
+
+		local_sources = []
+		for source in self.sources:
+			local_source = os.path.join (package_dir, source)
+			local_source_file = os.path.basename (local_source)
+			local_dest_file = os.path.join (package_dest_dir, local_source_file)
+			local_sources.append (local_dest_file)
+			
+			if os.path.isfile (local_dest_file):
+				log (1, 'using cached source: %s' % local_dest_file)
+			elif os.path.isfile (local_source):
+				log (1, 'copying local source: %s' % local_source_file)
+				shutil.copy2 (local_source, local_dest_file)
+			elif source.startswith (('http://', 'https://', 'ftp://')):
+				log (1, 'downloading remote source: %s' % source)
+				urllib.urlretrieve (source, local_dest_file)
+
+		self.sources = local_sources
+
+	def start_build (self):
+		Package.last_instance = None
+		
+		expand_macros (self, self)
+
+		profile = Package.profile
+
+		namever = '%s-%s' % (self.name, self.version)
+		package_dir = os.path.dirname (os.path.realpath (__file__))
+		package_dest_dir = os.path.join (profile.build_root, namever)
+		package_build_dir = os.path.join (package_dest_dir, '_build')
+		build_success_file = os.path.join (profile.build_root,
+			namever + '.success')
+
+		if os.path.exists (build_success_file):
+			print 'Skipping %s - already built' % namever
+			return
+
+		print 'Building %s on %s (%s CPU)' % (self.name, profile.host,
+			profile.cpu_count)
+
+		if not os.path.exists (profile.build_root) or \
+			not os.path.isdir (profile.build_root):
+			os.makedirs (profile.build_root, 0755)
+
+		shutil.rmtree (package_build_dir, ignore_errors = True)
+		os.makedirs (package_build_dir)
+
+		self._fetch_sources (package_dir, package_dest_dir)
+
+		os.chdir (package_build_dir)
+
+		self.prep ()
+		self.build ()
+		self.install ()
+
+		open (build_success_file, 'w').close ()
+
+	def sh (self, *commands):
+		for command in commands:
+			command = expand_macros (command, self)
+			log (1, command)
+			#if not Package.profile.verbose:
+			#	command = '( %s ) &>/dev/null' % command
+			run_shell (command)
+
+	def cd (self, dir):
+		dir = expand_macros (dir, self)
+		log (1, 'cd "%s"' % dir)
+		os.chdir (dir)
+
+	def prep (self):
+		if self.sources == None:
+			return
+		self.sh ('tar xf %{sources[0]}')
+		self.cd ('%{source_dir_name}')
+	
+	def build (self):
+		if self.sources == None:
+			return
+		self.sh ('%{configure} %{configure_flags}')
+		self.sh ('%{make}')
+
+	def install (self):
+		if self.sources == None:
+			return
+		self.sh ('%{makeinstall}')
+
+Package.default_sources = None
+
+# -------------------------------------
+# Package Templates
+# -------------------------------------
+
+class GnomePackage (Package):
+	def __init__ (self, name, version_major = '0', version_minor = '0',
+		configure_flags = None, sources = None, override_properties = None):
+		
+		self.version_major = version_major
+		self.version_minor = version_minor
+		
+		Package.__init__ (self, name, '%{version_major}.%{version_minor}',
+			configure_flags = configure_flags,
+			sources = sources,
+			override_properties = override_properties)
+
+GnomePackage.default_sources = [
+	'http://ftp.gnome.org/pub/gnome/sources/%{name}/%{version_major}/%{name}-%{version}.tar.gz'
+]
+
+class GnuPackage (Package): pass
+GnuPackage.default_sources = [
+	'http://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.gz'
+]
+
+class CairoGraphicsPackage (Package): pass
+CairoGraphicsPackage.default_sources = [
+	'http://cairographics.org/releases/%{name}-%{version}.tar.gz'
+]
+
+class ProjectPackage (Package):
+	def __init__ (self, project, name, version, configure_flags = None,
+		sources = None, override_properties = None):
+
+		self.project = project
+		Package.__init__ (self, name, version,
+			configure_flags = configure_flags,
+			sources = sources,
+			override_properties = override_properties)
+
+class SourceForgePackage (ProjectPackage): pass
+SourceForgePackage.default_sources = [
+	'http://downloads.sourceforge.net/sourceforge/%{project}/%{name}-%{version}.tar.gz'
+]
+
+class FreeDesktopPackage (ProjectPackage): pass
+FreeDesktopPackage.default_sources = [
+	'http://%{project}.freedesktop.org/releases/%{name}-%{version}.tar.gz'
+]
+
+class GstreamerPackage (ProjectPackage): pass
+GstreamerPackage.default_sources = [
+	'http://%{project}.freedesktop.org/src/%{name}/%{name}-%{version}.tar.gz'
+]
+
+class XiphPackage (ProjectPackage): pass
+XiphPackage.default_sources = [
+	'http://downloads.xiph.org/releases/%{project}/%{name}-%{version}.tar.gz'
+]
diff --git a/build/bundle/bockbuild/profile.py b/build/bundle/bockbuild/profile.py
new file mode 100644
index 0000000..a95dbe2
--- /dev/null
+++ b/build/bundle/bockbuild/profile.py
@@ -0,0 +1,38 @@
+import os
+import build
+from util import *
+from environment import Environment
+from package import *
+
+class Profile:
+	def __init__ (self):
+		self.name = 'default'
+		self.build_root = os.path.join (os.getcwd (), 'build-root')
+		self.prefix = os.path.join (self.build_root, '_install')
+		self.env = Environment (self)
+		self.env.set ('BUILD_PREFIX', self.prefix)
+		self.packages = []
+		self.cpu_count = get_cpu_count ()
+		self.host = get_host ()
+
+	def run (self):
+		build.main (self)
+	
+	def build (self):
+		log (0, 'Setting environment variables')
+		self.env.compile ()
+		self.env.export ()
+		for k in self.env.get_names ():
+			log (1, '%s = %s' % (k, os.getenv (k)))
+
+		Package.profile = self
+
+		pwd = os.getcwd ()
+		for path in self.packages:
+			os.chdir (pwd)
+			path = os.path.join (os.path.dirname (sys.argv[0]), path)
+			exec compile (open (path).read (), path, 'exec')
+			if Package.last_instance == None:
+				sys.exit ('%s does not provide a valid package.' % path)
+			Package.last_instance.start_build ()
+			Package.last_instance = None
diff --git a/build/bundle/bockbuild/unixprofile.py b/build/bundle/bockbuild/unixprofile.py
new file mode 100644
index 0000000..83fa166
--- /dev/null
+++ b/build/bundle/bockbuild/unixprofile.py
@@ -0,0 +1,31 @@
+from profile import Profile
+
+class UnixProfile (Profile):
+	def __init__ (self):
+		Profile.__init__ (self)
+		self.name = 'unix'
+
+		self.gcc_arch_flags = [ '-m32', '-arch i386' ]
+		self.gcc_flags = [ '-I%{prefix}/include' ]
+
+		self.env.set ('PATH', ':',
+			'%{prefix}/bin',
+			'/usr/bin',
+			'/bin')
+		
+		self.env.set ('CFLAGS', ' ',
+			'%{gcc_flags}', 
+			'%{gcc_arch_flags}')
+		self.env.set ('CXXFLAGS',        '%{env.CFLAGS}')
+		self.env.set ('CPPFLAGS',        '%{env.CFLAGS}')
+		self.env.set ('C_INCLUDE_PATH',  '%{prefix}/include')
+
+		self.env.set ('LD_LIBRARY_PATH', '%{prefix}/lib')
+		self.env.set ('LDFLAGS', ' ',
+			'-L%{prefix}/lib', 
+			'%{gcc_arch_flags}')
+
+		self.env.set ('ACLOCAL_FLAGS',   '-I%{prefix}/share/aclocal')
+		self.env.set ('PKG_CONFIG_PATH', ':',
+			'%{prefix}/lib/pkgconfig',
+			'%{prefix}/share/pkgconfig')
diff --git a/build/bundle/bockbuild/util.py b/build/bundle/bockbuild/util.py
new file mode 100644
index 0000000..a73f2f3
--- /dev/null
+++ b/build/bundle/bockbuild/util.py
@@ -0,0 +1,83 @@
+import re
+import glob
+import os
+import sys
+import subprocess
+
+def log (level, message):
+	if level == 0:
+		print '==> %s' % message
+	elif level == 1:
+		print '    + %s' % message
+	elif level == 2:
+		print '      - %s' % message
+
+def expand_macros (node, vars):
+	def sub_macro (m):
+		type = m.groups ()[0]
+		expr = m.groups ()[1]
+		if type == '%':
+			expr = 'self.' + expr
+		o = eval (expr, {}, { 'self': vars })
+		if o == None:
+			return ''
+		elif isinstance (o, (list, tuple)):
+			return ' '.join (o)
+		return str (o)
+
+	if hasattr (node, '__dict__'):
+		for k, v in node.__dict__.iteritems ():
+			if not k.startswith ('_'):
+				node.__dict__[k] = expand_macros (v, vars)
+	elif isinstance (node, dict):
+		for k, v in node.iteritems ():
+			node[k] = expand_macros (v, vars)
+	elif isinstance (node, (list, tuple)):
+		for i, v in enumerate (node):
+			node[i] = expand_macros (v, vars)
+	elif isinstance (node, str):
+		orig_node = node
+		iters = 0
+		while True:
+			v = re.sub ('(?<!\\\)([%$]){([^}]+)}',
+				sub_macro, node)
+			if v == node:
+				break
+			iters += 1
+			if iters >= 500:
+				sys.exit ('Too many macro substitutions, possible recursion:'
+					'\'%s\'' % orig_node)
+			node = v
+
+	return node
+
+def run_shell (cmd):
+	proc = subprocess.Popen (cmd, shell = True)
+	exit_code = os.waitpid (proc.pid, 0)[1]
+	if not exit_code == 0:
+		print
+		sys.exit ('ERROR: command exited with exit code %s: %s' % (exit_code, cmd))
+
+def backtick (cmd):
+	lines = []
+	for line in os.popen (cmd).readlines ():
+		lines.append (line.rstrip ('\r\n'))
+	return lines
+
+def get_host ():
+	search_paths = ['/usr/share', '/usr/local/share']
+	am_config_guess = []
+	for path in search_paths:
+		am_config_guess.extend (glob.glob (os.path.join (
+			path, os.path.join ('automake*', 'config.guess'))))
+	for config_guess in am_config_guess:
+		config_sub = os.path.join (os.path.dirname (config_guess), 'config.sub')
+		if os.access (config_guess, os.X_OK) and os.access (config_sub, os.X_OK):
+			return backtick ('%s %s' % (config_sub, backtick (config_guess)[0]))[0]
+	return 'python-%s' % os.name
+
+def get_cpu_count ():
+	try:
+		return os.sysconf ('SC_NPROCESSORS_CONF')
+	except:
+		return 1
diff --git a/build/bundle/packages.py b/build/bundle/packages.py
new file mode 100644
index 0000000..d7de5f3
--- /dev/null
+++ b/build/bundle/packages.py
@@ -0,0 +1,83 @@
+from bockbuild.darwinprofile import DarwinProfile
+
+class BansheePackages:
+	def __init__ (self):
+		# Toolchain
+		self.packages.extend ([
+			'packages/autoconf.py',
+			'packages/automake.py',
+			'packages/libtool.py',
+			'packages/gettext.py',
+			'packages/pkg-config.py'
+		])
+
+		# Base Libraries
+		self.packages.extend ([
+			# 'packages/libiconv.py',
+			'packages/libpng.py',
+			'packages/libjpeg.py',
+			'packages/libxml2.py',
+			'packages/freetype.py',
+			'packages/fontconfig.py',
+			'packages/pixman.py',
+			'packages/cairo.py',
+			'packages/glib.py',
+			'packages/pango.py',
+			'packages/atk.py',
+			'packages/intltool.py',
+			'packages/gtk+.py',
+			'packages/gconf-dummy.py',
+			'packages/libglade.py',
+			'packages/libproxy.py',
+			'packages/libsoup.py',
+			'packages/sqlite.py'
+		])
+
+		# Icons
+		self.packages.extend ([
+			'packages/librsvg.py',
+			'packages/icon-naming-utils.py',
+			'packages/hicolor-icon-theme.py',
+			'packages/tango-icon-theme.py'
+		])
+
+		# Codecs
+		self.packages.extend ([
+			'packages/libogg.py',
+			'packages/libvorbis.py',
+			'packages/flac.py',
+			'packages/libtheora.py',
+			'packages/speex.py',
+			'packages/wavpack.py',
+			'packages/taglib.py',
+		])
+
+		# GStreamer
+		self.packages.extend ([
+			'packages/liboil.py',
+			'packages/gstreamer.py',
+			'packages/gst-plugins-base.py',
+			'packages/gst-plugins-good.py'
+		])
+
+		if isinstance (self, DarwinProfile):
+			self.packages.extend ([
+				'packages/gst-plugins-bad.py',
+				'packages/gst-plugins-ugly.py'
+			])
+
+		# Mono
+		self.packages.extend ([
+			'packages/mono.py',
+			'packages/gtk-sharp.py',
+			'packages/mono-addins.py',
+			'packages/ndesk-dbus.py',
+			'packages/ndesk-dbus-glib.py',
+			'packages/taglib-sharp.py'
+		])
+
+		if isinstance (self, DarwinProfile):
+			self.packages.extend ([
+				'packages/ige-mac-integration.py',
+				'packages/ige-mac-integration-sharp.py'
+			])
diff --git a/build/bundle/packages/atk.py b/build/bundle/packages/atk.py
index cee6871..699c7a1 100644
--- a/build/bundle/packages/atk.py
+++ b/build/bundle/packages/atk.py
@@ -1,9 +1 @@
-package = {
-	'name':          'atk',
-	'version_major': '1.26',
-	'version_minor': '0',
-	'version':       '%{version_major}.%{version_minor}',
-	'sources': [
-		'http://ftp.gnome.org/pub/gnome/sources/%{name}/%{version_major}/%{name}-%{version}.tar.gz'
-	]
-}
+GnomePackage ('atk', version_major = '1.26', version_minor = '0')
diff --git a/build/bundle/packages/autoconf.py b/build/bundle/packages/autoconf.py
index c088612..e1c5372 100644
--- a/build/bundle/packages/autoconf.py
+++ b/build/bundle/packages/autoconf.py
@@ -1,7 +1 @@
-package = {
-	'name':    'autoconf',
-	'version': '2.65',
-	'sources': [
-		'http://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.bz2'
-	]
-}
+GnuPackage ('autoconf', '2.65')
diff --git a/build/bundle/packages/automake.py b/build/bundle/packages/automake.py
index 29b5839..5bedbb4 100644
--- a/build/bundle/packages/automake.py
+++ b/build/bundle/packages/automake.py
@@ -1,7 +1 @@
-package = {
-	'name':    'automake',
-	'version': '1.11.1',
-	'sources': [
-		'http://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.bz2'
-	]
-}
+GnuPackage ('automake', '1.11.1')
diff --git a/build/bundle/packages/cairo.py b/build/bundle/packages/cairo.py
index be59af0..449a754 100644
--- a/build/bundle/packages/cairo.py
+++ b/build/bundle/packages/cairo.py
@@ -1,27 +1,24 @@
-configure_args = [
-	'--enable-pdf'
-]
+class CairoPackage (CairoGraphicsPackage):
+	def __init__ (self):
+		Package.__init__ (self, 'cairo', '1.8.8')
+	
+	def build (self):
+		self.configure_flags = [
+			'--enable-pdf'
+		]
 
-if profile['name'] == 'osx':
-	configure_args.extend ([
-		'--enable-quartz',
-		'--disable-xlib=no',
-		'--without-x'
-	])
-elif profile['name'] == 'linux':
-	configure_args.extend ([
-		'--disable-quartz',
-		'--with-x'
-	])
+		if Package.profile.name == 'darwin':
+			self.configure_flags.extend ([
+				'--enable-quartz',
+				'--disable-xlib',
+				'--without-x'
+			])
+		elif Package.profile.name == 'linux':
+			self.configure_flags.extend ([
+				'--disable-quartz',
+				'--with-x'
+			])
 
-package = {
-	'name':    'cairo',
-	'version': '1.8.8',
-	'sources': [
-		'http://cairographics.org/releases/%{name}-%{version}.tar.gz'
-	],
-	'build': [
-		'%{__configure} ' + ' '.join (configure_args),
-		'%{__make}'
-	]
-}
+		Package.build (self)
+
+CairoPackage ()
diff --git a/build/bundle/packages/flac.py b/build/bundle/packages/flac.py
index f551e76..57a3ba6 100644
--- a/build/bundle/packages/flac.py
+++ b/build/bundle/packages/flac.py
@@ -1,18 +1,12 @@
-configure_flags = [
-	'--disable-cpplibs'
-]
+class FlacPackage (XiphPackage):
+	def __init__ (self):
+		XiphPackage.__init__ (self, 'flac', 'flac', '1.2.1',
+			configure_flags = [
+				'--disable-cpplibs'
+			]
+		)
 
-if profile['name'] == 'osx':
-	configure_flags.append ('--disable-asm-optimizations')
+		if Package.profile.name == 'darwin':
+			self.configure_flags.append ('--disable-asm-optimizations')
 
-package = {
-	'name':    'flac',
-	'version': '1.2.1',
-	'sources': [
-		'http://downloads.xiph.org/releases/%{name}/%{name}-%{version}.tar.gz'
-	],
-	'build': [
-		'%{__configure} ' + ' '.join (configure_flags),
-		'%{__make}'
-	]
-}
+FlacPackage ()
diff --git a/build/bundle/packages/fontconfig.py b/build/bundle/packages/fontconfig.py
index 19193d2..61a4ab5 100644
--- a/build/bundle/packages/fontconfig.py
+++ b/build/bundle/packages/fontconfig.py
@@ -1,11 +1,6 @@
-package = {
-	'name':    'fontconfig',
-	'version': '2.7.3',
-	'sources': [
+Package ('fontconfig', '2.7.3',
+	configure_flags = '--disable-docs',
+	sources = [
 		'http://www.fontconfig.org/release/%{name}-%{version}.tar.gz'
-	],
-	'build': [
-		'%{__configure} --disable-docs',
-		'%{__make}'
 	]
-}
+)
diff --git a/build/bundle/packages/freetype.py b/build/bundle/packages/freetype.py
index cc5bce2..daffca9 100644
--- a/build/bundle/packages/freetype.py
+++ b/build/bundle/packages/freetype.py
@@ -1,11 +1,3 @@
-package = {
-	'name':    'freetype',
-	'version': '2.3.11',
-	'sources': [
-		'http://downloads.sourceforge.net/sourceforge/%{name}/%{name}-%{version}.tar.gz'
-	],
-	'build': [
-		'./configure --prefix %{_prefix}',
-		'%{__make}'
-	]
-}
+SourceForgePackage ('%{name}', 'freetype', '2.3.11', override_properties = {
+	'configure': './configure --prefix %{prefix}'
+})
diff --git a/build/bundle/packages/gconf-dummy.py b/build/bundle/packages/gconf-dummy.py
index d89a3ba..88de163 100644
--- a/build/bundle/packages/gconf-dummy.py
+++ b/build/bundle/packages/gconf-dummy.py
@@ -1,10 +1,9 @@
-package = {
-	'name':    'gconf2-dummy',
-	'version': '2',
-	'sources': [],
-	'prep':    [],
-	'build':   [],
-	'install': [
-		'echo "AC_DEFUN([AM_GCONF_SOURCE_2],[])" > %{_prefix}/share/aclocal/gconf-2.m4'
-	]
-}
+class Gconf2DummyPackage (Package):
+	def __init__ (self):
+		Package.__init__ (self, 'gconf2-dummy', '2')
+	
+	def install (self):
+		self.sh ('echo "AC_DEFUN([AM_GCONF_SOURCE_2],[])" '
+			'> %{prefix}/share/aclocal/gconf-2.m4')
+
+Gconf2DummyPackage ()
diff --git a/build/bundle/packages/gettext.py b/build/bundle/packages/gettext.py
index aa089df..6de3b50 100644
--- a/build/bundle/packages/gettext.py
+++ b/build/bundle/packages/gettext.py
@@ -1,11 +1,5 @@
-package = {
-	'name':    'gettext',
-	'version': '0.17',
-	'sources': [
-		'http://ftp.gnu.org/pub/gnu/%{name}/%{name}-%{version}.tar.gz'
-	],
-	'build': [
-		'%{__configure} --disable-java --disable-libasprintf --disable-openmp',
-		'%{__make}'
-	]
-}
+GnuPackage ('gettext', '0.17', configure_flags = [
+	'--disable-java',
+	'--disable-libasprintf',
+	'--disable-openmp'
+])
diff --git a/build/bundle/packages/glib.py b/build/bundle/packages/glib.py
index a8f490e..cc5ec98 100644
--- a/build/bundle/packages/glib.py
+++ b/build/bundle/packages/glib.py
@@ -1,39 +1,44 @@
-package = {
-	'name':          'glib',
-	'version_major': '2.22',
-	'version_minor': '3',
-	'version':       '%{version_major}.%{version_minor}',
-	'macports_svn':  'http://svn.macports.org/repository/macports/trunk/dports/devel/glib2/files',
-	'sources': [
-		'http://ftp.gnome.org/pub/gnome/sources/%{name}/%{version_major}/%{name}-%{version}.tar.gz',
-	]
-}
+class GlibPackage (GnomePackage):
+	def __init__ (self):
+		GnomePackage.__init__ (self,
+			'glib',
+			version_major = '2.22',
+			version_minor = '3')
 
-if profile['name'] == 'osx':
-	package['sources'].extend ([
-		'%{macports_svn}/config.h.ed',
-		'%{macports_svn}/patch-configure.in.diff',
-		'%{macports_svn}/patch-glib-2.0.pc.in.diff',
-		'%{macports_svn}/patch-gi18n.h.diff',
-		'%{macports_svn}/patch-child-test.c.diff'
-	])
+		self.darwin = Package.profile.name == 'darwin'
+		self.macports_svn = 'http://svn.macports.org/repository/macports/trunk/dports/devel/glib2/files'
 
-	package['prep'] = [
-		'tar xf @{sources:0}',
-		'cd %{name}-%{version}'
-	]
+		if Package.profile.name == 'darwin':
+			self.sources.extend (['%{macports_svn}/' + s for s in [
+				'config.h.ed',
+				'patch-configure.in.diff',
+				'patch-glib-2.0.pc.in.diff',
+				'patch-gi18n.h.diff',
+				'patch-child-test.c.diff'
+			]])
 
-	package['prep'].extend (['patch -p0 < @{sources:%s}' % p
-		for p in range (2, len (package['sources']))])
+	def prep (self):
+		Package.prep (self)
+		if self.darwin:
+			for p in range (2, len (self.sources)):
+				self.sh ('patch -p0 < %{sources[' + str (p) + ']}')
+	
+	def build (self):
+		if not self.darwin:
+			Package.build (self)
+			return
 
-	package['build'] = [
-		'autoconf',
-		'%{__configure}',
-		'ed - config.h < @{sources:1}',
-		'%{__make}'
-	]
+		self.sh (
+			'autoconf',
+			'%{configure}',
+			'ed - config.h < %{sources[1]}',
+			'%{make}'
+		)
 
-	package['install'] = [
-		'%{__makeinstall}',
-		'rm %{_prefix}/lib/charset.alias'
-	]
+	def install (self):
+		Package.install (self)
+		if self.darwin:
+			# FIXME: necessary?
+			self.sh ('rm %{prefix}/lib/charset.alias')
+
+GlibPackage ()
diff --git a/build/bundle/packages/gst-plugins-bad.py b/build/bundle/packages/gst-plugins-bad.py
index 2720992..2ba82d5 100644
--- a/build/bundle/packages/gst-plugins-bad.py
+++ b/build/bundle/packages/gst-plugins-bad.py
@@ -1,18 +1,9 @@
-package = {
-	'name':    'gst-plugins-bad',
-	'version': '0.10.17',
-	'sources': [
-		'http://gstreamer.freedesktop.org/src/%{name}/%{name}-%{version}.tar.gz'
-	],
-	'build': [
-		'%{__configure}' \
-			' --disable-gtk-doc' \
-			' --with-plugins=quicktime' \
-			' --disable-apexsink' \
-			' --disable-bz2' \
-			' --disable-metadata' \
-			' --disable-oss4' \
-			' --disable-theoradec',
-		'%{__make}'
-	]
-}
+GstreamerPackage ('gstreamer', 'gst-plugins-bad', '0.10.13', configure_flags = [
+	' --disable-gtk-doc',
+	' --with-plugins=quicktime',
+	' --disable-apexsink',
+	' --disable-bz2',
+	' --disable-metadata',
+	' --disable-oss4',
+	' --disable-theoradec'
+])
diff --git a/build/bundle/packages/gst-plugins-base.py b/build/bundle/packages/gst-plugins-base.py
index 02f61c0..01debd4 100644
--- a/build/bundle/packages/gst-plugins-base.py
+++ b/build/bundle/packages/gst-plugins-base.py
@@ -1,28 +1,22 @@
-configure_flags = [
-	'--disable-gtk-doc',
-	'--disable-gio',
-	'--disable-gnome_vfs',
-	'--disable-pango'
-]
+class GstPluginsBasePackage (GstreamerPackage):
+	def __init__ (self):
+		GstreamerPackage.__init__ (self, 'gstreamer', 'gst-plugins-base',
+			'0.10.25', configure_flags = [
+				'--disable-gtk-doc',
+				'--disable-gio',
+				'--disable-gnome_vfs',
+				'--disable-pango'
+			]
+		)
 
-# FIXME: these should be passed on the Linux profile
-# when we do away with xvideo/xoverlay and replace
-# with Clutter and Cairo
-if profile['name'] == 'osx':
-	configure_flags.extend ([
-		'--disable-x',
-		'--disable-xvideo',
-		'--disable-xshm'
-	])
+		# FIXME: these should be passed on the Linux profile
+		# when we do away with xvideo/xoverlay and replace
+		# with Clutter and Cairo
+		if Package.profile.name == 'darwin':
+			self.configure_flags.extend ([
+				'--disable-x',
+				'--disable-xvideo',
+				'--disable-xshm'
+			])
 
-package = {
-	'name':    'gst-plugins-base',
-	'version': '0.10.25',
-	'sources': [
-		'http://gstreamer.freedesktop.org/src/%{name}/%{name}-%{version}.tar.gz'
-	],
-	'build': [
-		'%{__configure} ' + ' '.join (configure_flags), 
-		'%{__make}'
-	]
-}
+GstPluginsBasePackage ()
diff --git a/build/bundle/packages/gst-plugins-good.py b/build/bundle/packages/gst-plugins-good.py
index c68a0a5..00fd74a 100644
--- a/build/bundle/packages/gst-plugins-good.py
+++ b/build/bundle/packages/gst-plugins-good.py
@@ -1,30 +1,24 @@
-configure_flags = [
-	'--disable-gtk-doc',
-	'--disable-gdk_pixbuf',
-	'--disable-cairo',
-	'--disable-jpeg',
-	'--disable-libpng',
-	'--disable-annodex'
-]
+class GstPluginsGoodPackage (GstreamerPackage):
+	def __init__ (self):
+		GstreamerPackage.__init__ (self, 'gstreamer', 'gst-plugins-good',
+			'0.10.17', configure_flags = [
+				'--disable-gtk-doc',
+				'--disable-gdk_pixbuf',
+				'--disable-cairo',
+				'--disable-jpeg',
+				'--disable-libpng',
+				'--disable-annodex'
+			]
+		)
 
-# FIXME: these should be passed on the Linux profile
-# when we do away with xvideo/xoverlay and replace
-# with Clutter and Cairo
-if profile['name'] == 'osx':
-	configure_flags.extend ([
-		'--disable-x',
-		'--disable-xvideo',
-		'--disable-xshm'
-	])
+		# FIXME: these should be passed on the Linux profile
+		# when we do away with xvideo/xoverlay and replace
+		# with Clutter and Cairo
+		if Package.profile.name == 'darwin':
+			self.configure_flags.extend ([
+				'--disable-x',
+				'--disable-xvideo',
+				'--disable-xshm'
+			])
 
-package = {
-	'name':    'gst-plugins-good',
-	'version': '0.10.17',
-	'sources': [
-		'http://gstreamer.freedesktop.org/src/%{name}/%{name}-%{version}.tar.gz'
-	],
-	'build': [
-		'%{__configure} ' + ' '.join (configure_flags),
-		'%{__make}'
-	]
-}
+GstPluginsGoodPackage ()
diff --git a/build/bundle/packages/gst-plugins-ugly.py b/build/bundle/packages/gst-plugins-ugly.py
index 0959cc0..dfeca60 100644
--- a/build/bundle/packages/gst-plugins-ugly.py
+++ b/build/bundle/packages/gst-plugins-ugly.py
@@ -1,18 +1,12 @@
-package = {
-	'name':    'gst-plugins-ugly',
-	'version': '0.10.13',
-	'sources': [
-		'http://gstreamer.freedesktop.org/src/%{name}/%{name}-%{version}.tar.gz'
-	],
-	'build': [
-		'%{__configure}' \
-			' --disable-gtk-doc' \
-			' --disable-asfdemux' \
-			' --disable-dvdsub' \
-			' --disable-dvdlpcmdec' \
-			' --disable-iec958' \
-			' --disable-mpegstream' \
-			' --disable-realmedia',
-		'%{__make}'
-	]
-}
+# FIXME version is out of date from upstream, but GStreamer lost all
+# their tarballs, so falling back to the tarball from openSUSE,
+# which is also very out of date... should be 0.10.13
+GstreamerPackage ('gstreamer', 'gst-plugins-ugly', '0.10.12', configure_flags = [
+	' --disable-gtk-doc',
+	' --disable-asfdemux',
+	' --disable-dvdsub',
+	' --disable-dvdlpcmdec',
+	' --disable-iec958',
+	' --disable-mpegstream'
+	' --disable-realmedia'
+])
diff --git a/build/bundle/packages/gstreamer.py b/build/bundle/packages/gstreamer.py
index 27b740b..4b242f6 100644
--- a/build/bundle/packages/gstreamer.py
+++ b/build/bundle/packages/gstreamer.py
@@ -1,12 +1,3 @@
-package = {
-	'name':    'gstreamer',
-	'version': '0.10.25',
-	'sources': [
-		'http://gstreamer.freedesktop.org/src/%{name}/%{name}-%{version}.tar.gz'
-	],
-	'build': [
-		'%{__configure}' \
-			' --disable-gtk-doc',
-		'%{__make}'
-	]
-}
+GstreamerPackage ('gstreamer', 'gstreamer', '0.10.25', configure_flags = [
+	'--disable-gtk-doc'
+])
diff --git a/build/bundle/packages/gtk+.py b/build/bundle/packages/gtk+.py
index ca1cdf0..4f48d61 100644
--- a/build/bundle/packages/gtk+.py
+++ b/build/bundle/packages/gtk+.py
@@ -1,33 +1,27 @@
-configure_args = [
-	'--with-gdktarget=%{gdk_target}',
-	'--disable-cups',
-	'--without-libjasper',
-	'--without-libtiff'
-]
+class GtkPackage (GnomePackage):
+	def __init__ (self):
+		GnomePackage.__init__ (self, 'gtk+',
+			version_major = '2.18',
+			version_minor = '5',
+			configure_flags = [
+				'--with-gdktarget=%{gdk_target}',
+				'--disable-cups',
+				'--without-libjasper',
+				'--without-libtiff'
+			]
+		)
 
-package = {
-	'name':          'gtk+',
-	'version_major': '2.18',
-	'version_minor': '5',
-	'version':       '%{version_major}.%{version_minor}',
-	'sources': [
-		'http://ftp.gnome.org/pub/gnome/sources/%{name}/%{version_major}/%{name}-%{version}.tar.gz',
-	],
-	'prep': [
-		'tar xf @{sources:0}',
-		'cd %{name}-%{version}'
-	],
-	'build': [
-		'%{__configure} ' + ' '.join (configure_args),
-		'%{__make}'
-	]
-}
+		if Package.profile.name == 'darwin':
+			self.gdk_target = 'quartz'
+			self.sources.extend ([
+				'http://github.com/jralls/gtk-osx-build/raw/master/patches/gdk-quartz-input-window.patch'
+			])
+		elif Package.profile.name == 'linux':
+			self.gdk_target = 'x11'
 
-if profile['name'] == 'osx':
-	package['gdk_target'] = 'quartz'
-	package['sources'].extend ([
-		'http://github.com/jralls/gtk-osx-build/raw/master/patches/gdk-quartz-input-window.patch'
-	])
-	package['prep'].append ('patch -p1 < "@{sources:1}"')
-elif profile['name'] == 'linux':
-	package['gdk_target'] = 'x11'
+	def prep (self):
+		Package.prep (self)
+		if Package.profile.name == 'darwin':
+			self.sh ('patch -p1 < "%{sources[1]}"')
+
+GtkPackage ()
diff --git a/build/bundle/packages/gtk-sharp.py b/build/bundle/packages/gtk-sharp.py
index 3fcf382..60d15a9 100644
--- a/build/bundle/packages/gtk-sharp.py
+++ b/build/bundle/packages/gtk-sharp.py
@@ -1,27 +1,30 @@
-def svn_co_or_up (package):
-	os.chdir ('..')
-	if os.path.isdir ('svn'):
-		os.chdir ('svn')
-		os.system ('svn up')
-	else:
-		os.system ('svn co http://anonsvn.mono-project.com/source/branches/gtk-sharp-2-12-branch svn')
-		os.chdir ('svn')
-	os.chdir ('..')
+class GtkSharpPackage (Package):
+	def __init__ (self):
+		Package.__init__ (self, 'gtk-sharp', '2-12-branch')
+		self.branch = '212'
+		# self.sources = [
+		# 	'http://ftp.novell.com/pub/mono/sources/%{name}%{branch}/%{name}-%{version}.tar.bz2'
+		# ]
 
-package = {
-	'name':    'gtk-sharp',
-	'version': '2.12.10-svn',
-	'branch':  '212',
-	'sources': [
-		# 'http://ftp.novell.com/pub/mono/sources/%{name}%{branch}/%{name}-%{version}.tar.bz2'
-	],
-	'prep': [
-		svn_co_or_up,
-		'cp -r svn _build',
-		'cd _build/svn'
-	],
-	'build': [
-		'./bootstrap-2.12 --prefix=%{_prefix}',
-		'%{__make}'
-	]
-}
+	def svn_co_or_up (self):
+		self.cd ('..')
+		if os.path.isdir ('svn'):
+			self.cd ('svn')
+			self.sh ('svn up')
+		else:
+			self.sh ('svn co http://anonsvn.mono-project.com/source/branches/%{name}-%{version} svn')
+			self.cd ('svn')
+		self.cd ('..')
+
+	def prep (self):
+		self.svn_co_or_up ()
+		self.sh ('cp -r svn _build')
+		self.cd ('_build/svn')
+
+	def build (self):
+		self.sh (
+			'./bootstrap-2.12 --prefix=%{prefix}',
+			'%{make}'
+		)
+
+GtkSharpPackage ()
diff --git a/build/bundle/packages/hicolor-icon-theme.py b/build/bundle/packages/hicolor-icon-theme.py
index fcd1652..395d669 100644
--- a/build/bundle/packages/hicolor-icon-theme.py
+++ b/build/bundle/packages/hicolor-icon-theme.py
@@ -1,7 +1 @@
-package = {
-	'name':    'hicolor-icon-theme',
-	'version': '0.11',
-	'sources': [
-		'http://icon-theme.freedesktop.org/releases/%{name}-%{version}.tar.gz'
-	]
-}
+FreeDesktopPackage ('icon-theme', 'hicolor-icon-theme', '0.11')
diff --git a/build/bundle/packages/icon-naming-utils.py b/build/bundle/packages/icon-naming-utils.py
index 13787ef..36e3280 100644
--- a/build/bundle/packages/icon-naming-utils.py
+++ b/build/bundle/packages/icon-naming-utils.py
@@ -1,7 +1 @@
-package = {
-	'name':    'icon-naming-utils',
-	'version': '0.8.90',
-	'sources': [
-		'http://tango.freedesktop.org/releases/%{name}-%{version}.tar.gz'
-	]
-}
+FreeDesktopPackage ('tango', 'icon-naming-utils', '0.8.90')
diff --git a/build/bundle/packages/ige-mac-integration-sharp.py b/build/bundle/packages/ige-mac-integration-sharp.py
index 8a401cf..11e96e1 100644
--- a/build/bundle/packages/ige-mac-integration-sharp.py
+++ b/build/bundle/packages/ige-mac-integration-sharp.py
@@ -1,7 +1,3 @@
-package = {
-	'name':    'ige-mac-integration-sharp',
-	'version': '0.8.2',
-	'sources': [
-		'http://cloud.github.com/downloads/eoin/ige-mac-integration-sharp/%{name}-%{version}.tar.gz'
-	]
-}
+Package ('ige-mac-integration-sharp', '0.8.2', sources = [
+	'http://cloud.github.com/downloads/eoin/ige-mac-integration-sharp/%{name}-%{version}.tar.gz'
+])
diff --git a/build/bundle/packages/ige-mac-integration.py b/build/bundle/packages/ige-mac-integration.py
index 01e42a4..481ba02 100644
--- a/build/bundle/packages/ige-mac-integration.py
+++ b/build/bundle/packages/ige-mac-integration.py
@@ -1,7 +1 @@
-package = {
-	'name':    'ige-mac-integration',
-	'version': '0.8.6',
-	'sources': [
-		'http://downloads.sourceforge.net/sourceforge/gtk-osx/%{name}-%{version}.tar.gz'
-	]
-}
+SourceForgePackage ('gtk-osx', 'ige-mac-integration', '0.8.6')
diff --git a/build/bundle/packages/intltool.py b/build/bundle/packages/intltool.py
index cf2c07f..e2c982d 100644
--- a/build/bundle/packages/intltool.py
+++ b/build/bundle/packages/intltool.py
@@ -1,9 +1 @@
-package = {
-	'name':          'intltool',
-	'version_major': '0.40',
-	'version_minor': '6',
-	'version':       '%{version_major}.%{version_minor}',
-	'sources': [
-		'http://ftp.gnome.org/pub/gnome/sources/intltool/%{version_major}/%{name}-%{version}.tar.bz2'
-	]
-}
+GnomePackage ('intltool', version_major = '0.40', version_minor = '6')
diff --git a/build/bundle/packages/libglade.py b/build/bundle/packages/libglade.py
index 159ea80..3ba34e3 100644
--- a/build/bundle/packages/libglade.py
+++ b/build/bundle/packages/libglade.py
@@ -1,9 +1 @@
-package = {
-	'name':          'libglade',
-	'version_major': '2.6',
-	'version_minor': '4',
-	'version':       '%{version_major}.%{version_minor}',
-	'sources': [
-		'http://ftp.gnome.org/pub/gnome/sources/%{name}/%{version_major}/%{name}-%{version}.tar.bz2'
-	]
-}
+GnomePackage ('libglade', version_major = '2.6', version_minor = '4')
diff --git a/build/bundle/packages/libjpeg.py b/build/bundle/packages/libjpeg.py
index 3925ccf..42e6918 100644
--- a/build/bundle/packages/libjpeg.py
+++ b/build/bundle/packages/libjpeg.py
@@ -1,11 +1,6 @@
-package = {
-	'name':    'libjpeg',
-	'version': '7',
-	'sources': [
+Package ('libjpeg', '7',
+	source_dir_name = 'jpeg-%{version}',
+	sources = [
 		'http://www.ijg.org/files/jpegsrc.v%{version}.tar.gz'
-	],
-	'prep': [
-		'tar xf @{sources:0}',
-		'cd jpeg-%{version}'
 	]
-}
+)
diff --git a/build/bundle/packages/libogg.py b/build/bundle/packages/libogg.py
index c433102..68b8819 100644
--- a/build/bundle/packages/libogg.py
+++ b/build/bundle/packages/libogg.py
@@ -1,7 +1 @@
-package = {
-	'name':    'libogg',
-	'version': '1.1.4',
-	'sources': [
-		'http://downloads.xiph.org/releases/ogg/%{name}-%{version}.tar.gz'
-	]
-}
+XiphPackage ('ogg', 'libogg', '1.1.4')
diff --git a/build/bundle/packages/liboil.py b/build/bundle/packages/liboil.py
index 6243732..1a73aad 100644
--- a/build/bundle/packages/liboil.py
+++ b/build/bundle/packages/liboil.py
@@ -1,12 +1,10 @@
-package = {
-	'name':    'liboil',
-	'version': '0.3.16',
-	'sources': [
-		'http://liboil.freedesktop.org/download/%{name}-%{version}.tar.gz'
+Package ('liboil', '0.3.16',
+	sources = [
+		'http://download.banshee-project.org/misc/%{name}-%{version}.tar.gz'
+		# a bunch of liboil releases appear to be missing from the site...
+		# 'http://%{name}.freedesktop.org/download/%{name}-%{version}.tar.gz'
 	],
-	'build': [
-		'%{__configure}' \
-			' --disable-gtk-doc',
-		'%{__make}'
+	configure_flags = [
+		'--disable-gtk-doc'
 	]
-}
+)
diff --git a/build/bundle/packages/libpng.py b/build/bundle/packages/libpng.py
index ae97249..2f37d9f 100644
--- a/build/bundle/packages/libpng.py
+++ b/build/bundle/packages/libpng.py
@@ -1,11 +1,3 @@
-package = {
-	'name':    'libpng',
-	'version': '1.2.40',
-	'sources': [
-		'http://downloads.sourceforge.net/sourceforge/%{name}/%{name}-%{version}.tar.gz'
-	],
-	'build': [
-		'%{__configure} --enable-shared',
-		'%{__make}'
-	]
-}
+SourceForgePackage ('%{name}', 'libpng', '1.2.40', configure_flags = [
+	'--enable-shared'
+])
diff --git a/build/bundle/packages/libproxy.py b/build/bundle/packages/libproxy.py
index 770d4f2..706bb84 100644
--- a/build/bundle/packages/libproxy.py
+++ b/build/bundle/packages/libproxy.py
@@ -1,7 +1,3 @@
-package = {
-	'name':    'libproxy',
-	'version': '0.3.1',
-	'sources': [
-		'http://libproxy.googlecode.com/files/%{name}-%{version}.tar.bz2'
-	]
-}
+Package ('libproxy', '0.3.1', sources = [
+	'http://libproxy.googlecode.com/files/%{name}-%{version}.tar.bz2'
+])
diff --git a/build/bundle/packages/librsvg.py b/build/bundle/packages/librsvg.py
index 056d3b7..f12652c 100644
--- a/build/bundle/packages/librsvg.py
+++ b/build/bundle/packages/librsvg.py
@@ -1,9 +1 @@
-package = {
-	'name':          'librsvg',
-	'version_major': '2.26',
-	'version_minor': '0',
-	'version':       '%{version_major}.%{version_minor}',
-	'sources': [
-		'http://ftp.gnome.org/pub/gnome/sources/%{name}/%{version_major}/%{name}-%{version}.tar.gz',
-	]
-}
+GnomePackage ('librsvg', version_major = '2.26', version_minor = '0')
diff --git a/build/bundle/packages/libsoup.py b/build/bundle/packages/libsoup.py
index 648e989..3698462 100644
--- a/build/bundle/packages/libsoup.py
+++ b/build/bundle/packages/libsoup.py
@@ -1,16 +1,5 @@
-package = {
-	'name':         'libsoup',
-	'version_major': '2.28',
-	'version_minor': '2',
-	'version':       '%{version_major}.%{version_minor}',
-	'sources': [
-		'http://ftp.gnome.org/pub/gnome/sources/libsoup/%{version_major}/%{name}-%{version}.tar.bz2'
-	],
-	'build': [
-		'%{__configure}' \
-			' --without-gnome' \
-			' --disable-gtk-doc' \
-			' --disable-ssl',
-		'%{__make}'
-	]
-}
+GnomePackage ('libsoup', '2.28', '2', configure_flags = [
+	' --without-gnome',
+	' --disable-gtk-doc',
+	' --disable-ssl'
+])
diff --git a/build/bundle/packages/libtheora.py b/build/bundle/packages/libtheora.py
index 76260a4..672e62a 100644
--- a/build/bundle/packages/libtheora.py
+++ b/build/bundle/packages/libtheora.py
@@ -1,7 +1 @@
-package = {
-	'name':    'libtheora',
-	'version': '1.1beta3',
-	'sources': [
-		'http://downloads.xiph.org/releases/theora/%{name}-%{version}.tar.gz'
-	]
-}
+XiphPackage ('theora', 'libtheora', '1.1beta3')
diff --git a/build/bundle/packages/libtool.py b/build/bundle/packages/libtool.py
index cf80008..eaa318f 100644
--- a/build/bundle/packages/libtool.py
+++ b/build/bundle/packages/libtool.py
@@ -1,7 +1 @@
-package = {
-	'name':    'libtool',
-	'version': '2.2.6b',
-	'sources': [
-		'http://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.gz'
-	]
-}
+GnuPackage ('libtool', '2.2.6b')
diff --git a/build/bundle/packages/libvorbis.py b/build/bundle/packages/libvorbis.py
index 73a3e41..3d6fa20 100644
--- a/build/bundle/packages/libvorbis.py
+++ b/build/bundle/packages/libvorbis.py
@@ -1,7 +1 @@
-package = {
-	'name':    'libvorbis',
-	'version': '1.2.3',
-	'sources': [
-		'http://downloads.xiph.org/releases/vorbis/%{name}-%{version}.tar.gz'
-	]
-}
+XiphPackage ('vorbis', 'libvorbis', '1.2.3')
diff --git a/build/bundle/packages/libxml2.py b/build/bundle/packages/libxml2.py
index c8c9b7b..e62697d 100644
--- a/build/bundle/packages/libxml2.py
+++ b/build/bundle/packages/libxml2.py
@@ -1,11 +1,6 @@
-package = {
-	'name':    'libxml2',
-	'version': '2.7.6',
-	'sources': [
+Package ('libxml2', '2.7.6',
+	configure_flags = [ '--with-python=no' ],
+	sources = [
 		'ftp://xmlsoft.org/%{name}/%{name}-%{version}.tar.gz'			
-	],
-	'build': [
-		'%{__configure} --with-python=no',
-		'%{__make}'
 	]
-}
+)
diff --git a/build/bundle/packages/mono-addins.py b/build/bundle/packages/mono-addins.py
index 5f704d8..ead5207 100644
--- a/build/bundle/packages/mono-addins.py
+++ b/build/bundle/packages/mono-addins.py
@@ -1,15 +1,4 @@
-package = {
-	'name':    'mono-addins',
-	'version': '0.4',
-	'sources': [
-		'http://ftp.novell.com/pub/mono/sources/%{name}/%{name}-%{version}.zip'
-	],
-	'prep': [
-		'unzip @{sources:0}',
-		'cd %{name}-%{version}'
-	],
-	'build': [
-		'%{__configure}',
-		'make'
-	]
-}
+Package ('mono-addins', '0.4',
+	sources = [ 'http://ftp.novell.com/pub/mono/sources/%{name}/%{name}-%{version}.zip' ],
+	override_properties = { 'make': 'make' }
+)
diff --git a/build/bundle/packages/mono.py b/build/bundle/packages/mono.py
index 9fd4a3e..21759e4 100644
--- a/build/bundle/packages/mono.py
+++ b/build/bundle/packages/mono.py
@@ -1,27 +1,21 @@
-configure_flags = [
-	'--with-jit=yes',
-	'--with-ikvm=no',
-	'--with-mcs-docs=no',
-	'--with-moonlight=no',
-	'--enable-quiet-build'
-]
+class MonoPackage (Package):
+	def __init__ (self):
+		Package.__init__ (self, 'mono', '2.6.1',
+			sources = [
+				'http://ftp.novell.com/pub/%{name}/sources/%{name}/%{name}-%{version}.tar.bz2'
+			],
+			configure_flags = [
+				'--with-jit=yes',
+				'--with-ikvm=no',
+				'--with-mcs-docs=no',
+				'--with-moonlight=no',
+				'--enable-quiet-build'
+			]
+		)
+	
+	def install (self):
+		Package.install (self)
+		if Package.profile.name == 'darwin':
+			self.sh ('sed -ie "s/libcairo.so.2/libcairo.2.dylib/" "%{prefix}/etc/mono/config"')
 
-package = {
-	'name':    'mono',
-	'version': '2.6.1',
-	'sources': [
-		'http://ftp.novell.com/pub/%{name}/sources/%{name}/%{name}-%{version}.tar.bz2'
-	],
-	'build': [
-		'%{__configure} ' + ' '.join (configure_flags),
-		'%{__make}'
-	],
-	'install': [
-		'%{__makeinstall}'
-	]
-}
-
-if profile['name'] == 'osx':
-	package['install'].extend ([
-		'sed -ie "s/libcairo.so.2/libcairo.2.dylib/" "%{_prefix}/etc/mono/config"'
-	])
+MonoPackage ()
diff --git a/build/bundle/packages/ndesk-dbus-glib.py b/build/bundle/packages/ndesk-dbus-glib.py
index 33c8a92..51cb652 100644
--- a/build/bundle/packages/ndesk-dbus-glib.py
+++ b/build/bundle/packages/ndesk-dbus-glib.py
@@ -1,7 +1,3 @@
-package = {
-	'name':    'ndesk-dbus-glib',
-	'version': '0.4.1',
-	'sources': [
-		'http://www.ndesk.org/archive/dbus-sharp/%{name}-%{version}.tar.gz'
-	]
-}
+Package ('ndesk-dbus-glib', '0.4.1', sources = [
+	'http://www.ndesk.org/archive/dbus-sharp/%{name}-%{version}.tar.gz'
+])
diff --git a/build/bundle/packages/ndesk-dbus.py b/build/bundle/packages/ndesk-dbus.py
index 758e850..0e6bd7b 100644
--- a/build/bundle/packages/ndesk-dbus.py
+++ b/build/bundle/packages/ndesk-dbus.py
@@ -1,7 +1,3 @@
-package = {
-	'name':    'ndesk-dbus',
-	'version': '0.6.0',
-	'sources': [
-		'http://www.ndesk.org/archive/dbus-sharp/%{name}-%{version}.tar.gz'
-	]
-}
+Package ('ndesk-dbus', '0.6.0', sources = [
+	'http://www.ndesk.org/archive/dbus-sharp/%{name}-%{version}.tar.gz'
+])
diff --git a/build/bundle/packages/pango.py b/build/bundle/packages/pango.py
index 45ef478..42ce6ee 100644
--- a/build/bundle/packages/pango.py
+++ b/build/bundle/packages/pango.py
@@ -1,14 +1,14 @@
-package = {
-	'name':          'pango',
-	'version_major': '1.26',
-	'version_minor': '2',
-	'version':       '%{version_major}.%{version_minor}',
-	'sources': [
-		'http://ftp.gnome.org/pub/gnome/sources/%{name}/%{version_major}/%{name}-%{version}.tar.gz'
+GnomePackage ('pango',
+	version_major = '1.26',
+	version_minor = '2',
+	configure_flags = [
+		'--without-x',
+		'--with-included-modules=basic-atsui'
 	],
-	'build': [
-		'%{__configure} --without-x --with-included-modules=basic-atsui',
-		'%{__make} -k -C modules || true',
-		'%{__make}'
-	]
-}
+	override_properties = {
+		'make':
+			'( make -j%s -k -C modules || true ); '
+			'make -j%s' % \
+				(Package.profile.cpu_count, Package.profile.cpu_count)
+	}
+)
diff --git a/build/bundle/packages/pixman.py b/build/bundle/packages/pixman.py
index 63dcd5f..19de59f 100644
--- a/build/bundle/packages/pixman.py
+++ b/build/bundle/packages/pixman.py
@@ -1,7 +1 @@
-package = {
-	'name':    'pixman',
-	'version': '0.17.2',
-	'sources': [
-		'http://www.cairographics.org/releases/%{name}-%{version}.tar.gz'
-	]
-}
+CairoGraphicsPackage ('pixman', '0.17.2')
diff --git a/build/bundle/packages/pkg-config.py b/build/bundle/packages/pkg-config.py
index d1543ff..10432c1 100644
--- a/build/bundle/packages/pkg-config.py
+++ b/build/bundle/packages/pkg-config.py
@@ -1,7 +1,3 @@
-package = {
-	'name':    'pkg-config',
-	'version': '0.23',
-	'sources': [
-		'http://pkgconfig.freedesktop.org/releases/%{name}-%{version}.tar.gz'
-	]
-}
+Package ('pkg-config', '0.23', sources = [
+	'http://pkgconfig.freedesktop.org/releases/%{name}-%{version}.tar.gz'
+])
diff --git a/build/bundle/packages/speex.py b/build/bundle/packages/speex.py
index b0fb308..bd16c8b 100644
--- a/build/bundle/packages/speex.py
+++ b/build/bundle/packages/speex.py
@@ -1,7 +1 @@
-package = {
-	'name':    'speex',
-	'version': '1.2rc1',
-	'sources': [
-		'http://downloads.xiph.org/releases/%{name}/%{name}-%{version}.tar.gz'
-	]
-}
+XiphPackage ('speex', 'speex', '1.2rc1')
diff --git a/build/bundle/packages/sqlite.py b/build/bundle/packages/sqlite.py
index 43fa3b0..b3c6950 100644
--- a/build/bundle/packages/sqlite.py
+++ b/build/bundle/packages/sqlite.py
@@ -1,7 +1,3 @@
-package = {
-	'name':    'sqlite',
-	'version': '3.6.21',
-	'sources': [
-		'http://www.sqlite.org/sqlite-amalgamation-%{version}.tar.gz'
-	]
-}
+Package ('sqlite', '3.6.21', sources = [
+	'http://www.sqlite.org/sqlite-amalgamation-%{version}.tar.gz'
+])
diff --git a/build/bundle/packages/taglib-sharp.py b/build/bundle/packages/taglib-sharp.py
index 3bba2e2..d761de3 100644
--- a/build/bundle/packages/taglib-sharp.py
+++ b/build/bundle/packages/taglib-sharp.py
@@ -1,12 +1,4 @@
-package = {
-	'name':    'taglib-sharp',
-	'version': '2.0.3.3',
-	'sources': [
-		'http://download.banshee-project.org/%{name}/%{version}/%{name}-%{version}.tar.gz'
-	],
-	'build': [
-		'%{__configure}' \
-			' --disable-docs',
-		'%{__make}'
-	]
-}
+Package ('taglib-sharp', '2.0.3.3',
+	sources = [ 'http://download.banshee-project.org/%{name}/%{version}/%{name}-%{version}.tar.gz' ],
+	configure_flags = [ '--disable-docs' ]
+)
diff --git a/build/bundle/packages/taglib.py b/build/bundle/packages/taglib.py
index 4c15493..daa32e4 100644
--- a/build/bundle/packages/taglib.py
+++ b/build/bundle/packages/taglib.py
@@ -1,7 +1,3 @@
-package = {
-	'name':    'taglib',
-	'version': '1.6',
-	'sources': [
-		'http://developer.kde.org/~wheeler/files/src/%{name}-%{version}.tar.gz'
-	]
-}
+Package ('taglib', '1.6', sources = [
+	'http://developer.kde.org/~wheeler/files/src/%{name}-%{version}.tar.gz'
+])
diff --git a/build/bundle/packages/tango-icon-theme.py b/build/bundle/packages/tango-icon-theme.py
index 9ec4f87..cf3151b 100644
--- a/build/bundle/packages/tango-icon-theme.py
+++ b/build/bundle/packages/tango-icon-theme.py
@@ -1,11 +1,4 @@
-package = {
-	'name':    'tango-icon-theme',
-	'version': '0.8.90',
-	'sources': [
-		'http://tango.freedesktop.org/releases/%{name}-%{version}.tar.gz'
-	],
-	'build': [
-		'%{__configure} --enable-png-creation --disable-icon-framing',
-		'%{__make}'
-	]
-}
+FreeDesktopPackage ('tango', 'tango-icon-theme', '0.8.90', configure_flags = [
+	'--enable-png-creation',
+	'--disable-icon-framing'
+])
diff --git a/build/bundle/packages/wavpack.py b/build/bundle/packages/wavpack.py
index 8535f37..e42e33e 100644
--- a/build/bundle/packages/wavpack.py
+++ b/build/bundle/packages/wavpack.py
@@ -1,7 +1,3 @@
-package = {
-	'name':    'wavpack',
-	'version': '4.60.1',
-	'sources': [
-		'http://www.wavpack.com/%{name}-%{version}.tar.bz2'
-	]
-}
+Package ('wavpack', '4.60.1', sources = [
+	'http://www.wavpack.com/%{name}-%{version}.tar.bz2'
+])
diff --git a/build/bundle/profile.darwin.py b/build/bundle/profile.darwin.py
new file mode 100755
index 0000000..8b6c33b
--- /dev/null
+++ b/build/bundle/profile.darwin.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python -B
+
+from bockbuild.darwinprofile import DarwinProfile
+from packages import BansheePackages
+
+class BansheeDarwinProfile (DarwinProfile, BansheePackages):
+	def __init__ (self):
+		DarwinProfile.__init__ (self)
+		BansheePackages.__init__ (self)
+
+BansheeDarwinProfile ().build ()
diff --git a/build/bundle/profile.linux.py b/build/bundle/profile.linux.py
old mode 100644
new mode 100755
index 4dcdbaa..6558a08
--- a/build/bundle/profile.linux.py
+++ b/build/bundle/profile.linux.py
@@ -1,91 +1,15 @@
-profile = {
-	'name':         'linux',
-	'build_root':   os.path.join (os.getcwd (), 'build-root'),
-	'prefix':       '%{build_root}/_install'
-}
+#!/usr/bin/env python -B
 
-if not os.path.isdir ('/usr/include/alsa'):
-	sys.exit ('You must have the ALSA headers installed. (/usr/include/alsa)')
+from bockbuild.unixprofile import UnixProfile
+from packages import BansheePackages
 
-# gcc_arch_flags = [ '-m32', '-arch i386' ]
-gcc_arch_flags = []
-gcc_flags = [
-	'-I%{prefix}/include'
-]
-gcc_flags.extend (gcc_arch_flags)
+class BansheeLinuxProfile (UnixProfile, BansheePackages):
+	def __init__ (self):
+		UnixProfile.__init__ (self)
+		BansheePackages.__init__ (self)
 
-profile['environ'] = {
-	'BUILD_PREFIX':    '%{prefix}',
-	'PATH':            '%{prefix}/bin:/usr/bin:/bin',
+		import os
+		if not os.path.isdir ('/usr/include/alsa'):
+			raise IOError ('You must have the ALSA headers installed. (/usr/include/alsa)')
 
-	'CFLAGS':          ' '.join (gcc_flags),
-	'CXXFLAGS':        '%{CFLAGS}',
-	'CPPFLAGS':        '%{CFLAGS}',
-	'C_INCLUDE_PATH':  '%{prefix}/include',
-
-	'LD_LIBRARY_PATH': '%{prefix}/lib',
-	'LDFLAGS':         '-L%{prefix}/lib ' + ' '.join (gcc_arch_flags),
-
-	'ACLOCAL_FLAGS':   '-I%{prefix}/share/aclocal',
-
-	'PKG_CONFIG_PATH': '%{prefix}/lib/pkgconfig:%{prefix}/share/pkgconfig'
-}
-
-profile['packages'] = [
-	# Base dependencies
-	'packages/autoconf.py',
-	'packages/automake.py',
-	'packages/libtool.py',
-	'packages/gettext.py',
-	'packages/pkg-config.py',
-	'packages/libpng.py',
-	'packages/libjpeg.py',
-	'packages/libxml2.py',
-	'packages/freetype.py',
-	'packages/fontconfig.py',
-	'packages/pixman.py',
-	'packages/cairo.py',
-	'packages/glib.py',
-	'packages/pango.py',
-	'packages/atk.py',
-	'packages/intltool.py',
-	'packages/gtk+.py',
-	'packages/gconf-dummy.py',
-	'packages/libglade.py',
-	'packages/libproxy.py',
-	'packages/libsoup.py',
-	'packages/sqlite.py',
-	'packages/mono.py',
-
-	# Icons
-	'packages/librsvg.py',
-	'packages/icon-naming-utils.py',
-	'packages/hicolor-icon-theme.py',
-	'packages/tango-icon-theme.py',
-
-	# Xiph codecs/formats
-	'packages/libogg.py',
-	'packages/libvorbis.py',
-	'packages/flac.py',
-	'packages/libtheora.py',
-	'packages/speex.py',
-
-	# Various formats
-	'packages/wavpack.py',
-	'packages/taglib.py',
-
-	# GStreamer
-	'packages/liboil.py',
-	'packages/gstreamer.py',
-	'packages/gst-plugins-base.py',
-	'packages/gst-plugins-good.py',
-
-	# Managed Deps
-	'packages/gtk-sharp.py',
-	'packages/mono-addins.py',
-	'packages/ndesk-dbus.py',
-	'packages/ndesk-dbus-glib.py',
-	'packages/taglib-sharp.py',
-
-	# 'packages/banshee.py'
-]
+BansheeLinuxProfile ().run ()



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]