diff options
Diffstat (limited to 'src/SConscript')
-rw-r--r-- | src/SConscript | 810 |
1 files changed, 810 insertions, 0 deletions
diff --git a/src/SConscript b/src/SConscript new file mode 100644 index 0000000000..514609c518 --- /dev/null +++ b/src/SConscript @@ -0,0 +1,810 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import sys +import SCons +import shutil +import subprocess +import time +import SCons.Script as SCons + +from build import util, depends + +mixxx_version = util.get_mixxx_version() +branch_name = util.get_branch_name() +vcs_revision = util.get_revision() +vcs_name = util.get_current_vcs() +print "WE ARE IN:", os.getcwd() +print "Building ", branch_name, " - rev.", vcs_revision + +plugins = [] + +# Grab these from the SConstruct above us +Import('build') +Import('sources') +Import('soundsource_plugins') +Import('mixxxminimal_plugins') + +env = build.env +flags = build.flags + +#Tell SCons to build Mixxx +#========================= +if build.platform_is_windows: + dist_dir = 'dist%s' % build.bitwidth + # Populate the stuff that changes in the .rc file + fo = open(File('#src/mixxx.rc.include').abspath, "w") + + str_list = [] + str_list.append('#define VER_FILEVERSION ') + # Remove anything after ~ or - in the version number and replace the dots with commas + str_list.append(mixxx_version.partition('~')[0].partition('-')[0].replace('.',',')) + str_list.append(','+str(vcs_revision)+'\n') + + str_list.append('#define VER_PRODUCTVERSION ') + str_list.append(mixxx_version.partition('~')[0].partition('-')[0].replace('.',',')) + str_list.append(','+str(vcs_revision)+'\n') + + import datetime + now = datetime.datetime.now() + str_list.append('#define CUR_YEAR "'+str(now.year)+'"\n\n') + + if build.msvcdebug: + str_list.append('#define DEBUG 1\n') + if 'pre' in mixxx_version.lower(): + str_list.append('#define PRERELEASE 1\n') + + fo.write(''.join(str_list)) + fo.close() + + mixxx_bin = env.Program('mixxx', + [sources, env.RES('#src/mixxx.rc')], + LINKCOM = [env['LINKCOM'], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;1']) +else: + mixxx_bin = env.Program('mixxx', sources) + +def build_tests(): + test_files = Glob('test/*.cpp', strings=True) + test_env = env.Clone() + test_env.Append(CPPPATH="#lib/gtest-1.5.0/include") + test_env.Append(CPPPATH="#lib/gmock-1.5.0/include") + test_files = [test_env.StaticObject(filename) \ + if filename !='main.cpp' else filename + for filename in test_files] + mixxx_sources = [filename for filename in sources if filename != 'main.cpp'] + test_sources = (test_files + mixxx_sources) + + env.Append(LIBPATH="#lib/gtest-1.5.0/lib") + env.Append(LIBS = 'gtest') + + env.Append(LIBPATH="#lib/gmock-1.5.0/lib") + env.Append(LIBS = 'gmock') + + env.Program(target='mixxx-test', source=test_sources) + + Command("../mixxx-test", "./mixxx-test", Copy("$TARGET", "$SOURCE")) + +def run_tests(): + ret = Execute("./mixxx-test") + if ret != 0: + print "WARNING: Not all tests pass. See mixxx-test output." + Exit(ret) + +if int(build.flags['test']): + print "Building tests." + build_tests() + +if 'test' in BUILD_TARGETS: + print "Running tests." + run_tests() + +def osx_construct_version(build, mixxx_version, branch_name, vcs_revision): + # In release mode, we only use the version. + if build.build_is_release: + return mixxx_version + elif branch_name.startswith('release-'): + return '%s-%s%s' % (mixxx_version, vcs_name, vcs_revision) + # In a debug build, include the branch name and revision number + return "%s-%s-%s%s" % (mixxx_version, branch_name, vcs_name, vcs_revision) + +def ubuntu_construct_version(build, mixxx_version, branch_name, vcs_revision, + ubuntu_version): + # Underscores are not ok in version names, dashes are fine though. + if branch_name: + branch_name = branch_name.replace('_', '-') + # In release mode, we only use the version and ubuntu_version + if build.build_is_release: + return "%s-%s" % (mixxx_version, ubuntu_version) + elif branch_name.startswith('release-'): + return "%s-%s%s" % (mixxx_version, vcs_name, vcs_revision) + # In a debug build, include the branch name and revision number + return "%s-%s~%s~%s%s" % (mixxx_version, ubuntu_version, + branch_name, vcs_name, vcs_revision) + +def windows_construct_version(build, mixxx_version, branch_name, vcs_revision): + # In release mode, we only use the version + if build.build_is_release: + return mixxx_version + elif branch_name.startswith('release-'): + return '%s-%s%s' % (mixxx_version, vcs_name, vcs_revision) + # In a debug build, include the branch name and revision number + return "%s-%s-%s%s" % (mixxx_version, branch_name, vcs_name, vcs_revision) + +#Set up the install target +#========================= + +# flags['prefix'] = ARGUMENTS.get('prefix', '/usr/local') +# if not os.path.exists(flags['prefix']): +# print "Error: Prefix path does not exist!" +# Exit(1) +# else: +# unix_share_path = flags['prefix'] + "/share" +# unix_bin_path = flags['prefix'] + "/bin" + +#Mixxx binary +binary_files = mixxx_bin; + +# Mixxx essential resource files +resource_files = Glob('#res/schema.xml') + +#Soundsource plugins +soundsource_plugin_files = soundsource_plugins + +#VAMP beat tracking and key detection plugin +libmixxxminimal_vamp_plugin = mixxxminimal_plugins + +#Skins +skin_files = Glob('#res/skins/*') + +#Controller mappings +controllermappings_files = Glob('#res/controllers/*') + +# Translation files +translation_files = Glob('#res/translations/*.qm') + +#Keyboard mapping(s) +keyboardmappings_files = Glob('#res/keyboard/*') + +#Promo tracks +promotracks_files = Glob('#res/promo/*') + +#LADSPA shizzle +ladspapresets_files = Glob('#res/ladspa_presets/*') + +#Documentation +docs_files = Glob('#./LICENSE') +docs_files += Glob('#./README') +docs_files += Glob('#./Mixxx-Manual.pdf') + +#.desktop file for KDE/GNOME menu +dotdesktop_files = Glob('#src/mixxx.desktop') + +#Icon file for menu entry +icon_files = Glob('#res/images/mixxx-icon.png') + +#Images for preferences dialog +image_files = Glob('#res/images/preferences/*') # These are compiled in to the "mixxx" binary through mixxx.qrc + +#Windows DLLs + +# TODO: Use reference to SharedLibrary for libsndfile and others, glob only gets +# all files on 2+ builds after a clean. +if build.toolchain_is_msvs: + mixxx_winlib_path = SCons.ARGUMENTS.get('winlib', '..\\..\\..\\mixxx-win32lib-msvc90-release') + # skip the MSVC DLLs incase they're in there too + dll_files = Glob('%s/[!"msvc"]*.dll' % mixxx_winlib_path) +elif build.crosscompile and build.platform_is_windows and build.toolchain_is_gnu: + # We're cross-compiling, grab these from the crosscompile bin + # folder. How should we be doing this? + dll_files = Glob('#/../../mixxx-win%slib-crossmingw' % build.bitwidth) +elif build.crosscompile and build.platform_is_osx: + # Glob appropriate dylib files. We have 4 different library types, + # x86_64, x86, powerpc, powerpc64 + dylib_files = Glob('#/../../mixxx-osx-%s-crossmingw' % build.machine) +else: + dll_files = list() # dll_files += on the next line required dll_files to exist + +if build.msvcdebug: + dll_files += Split("""$QTDIR/lib/QtWebKitd4.dll""") +else: + dll_files += Split("""$QTDIR/lib/QtWebKit4.dll""") + +if build.msvcdebug: + dll_files += Split("""$QTDIR/lib/QtCored4.dll + $QTDIR/lib/QtGuid4.dll + $QTDIR/lib/QtNetworkd4.dll + $QTDIR/lib/QtOpenGLd4.dll + $QTDIR/lib/QtSqld4.dll + $QTDIR/lib/QtXmld4.dll + $QTDIR/lib/QtXmlPatternsd4.dll + $QTDIR/lib/QtSvgd4.dll + $QTDIR/lib/phonond4.dll + $QTDIR/lib/QtScriptd4.dll""") +else: + # if not int(build.flags['staticlibs']): + dll_files += Split("""$QTDIR/lib/QtCore4.dll + $QTDIR/lib/QtGui4.dll + $QTDIR/lib/QtNetwork4.dll + $QTDIR/lib/QtOpenGL4.dll + $QTDIR/lib/QtSql4.dll + $QTDIR/lib/QtXml4.dll + $QTDIR/lib/QtXmlPatterns4.dll + $QTDIR/lib/QtSvg4.dll + $QTDIR/lib/phonon4.dll + $QTDIR/lib/QtScript4.dll""") + +if int(flags.get('sqlitedll', 0)): + if build.msvcdebug: + sqldll_files = Split("""$QTDIR/plugins/sqldrivers/qsqlited4.dll""") #Qt SQLite plugin + else: + sqldll_files = Split("""$QTDIR/plugins/sqldrivers/qsqlite4.dll""") #Qt SQLite plugin + +if build.platform_is_linux or build.platform_is_bsd: + flags['prefix'] = ARGUMENTS.get('prefix', '/usr/local') + if not os.path.exists(flags['prefix']): + print "Error: Prefix path does not exist!" + Exit(1) + else: + #install_root is used in Debian/Ubuntu packaging (check the debian/rules file in the Ubuntu package) + #Basically, the flags['prefix'] is compiled into strings in Mixxx, whereas the install_root is not. When you're + #building a Debian package, pbuilder wants to install Mixxx to a temporary directory, but you still need + #the compiled-in strings using /usr as the prefix. That's why we have install_root and flags['prefix']. + install_root = ARGUMENTS.get('install_root', flags['prefix']) + print "Install root: " + install_root + unix_share_path = os.path.join(install_root, 'share') + unix_bin_path = os.path.join(install_root, 'bin') + unix_lib_path = os.path.join(install_root, 'lib') + + binary = env.Install(unix_bin_path, binary_files) + resource = env.Install(os.path.join(unix_share_path, 'mixxx'), resource_files) + skins = env.Install(os.path.join(unix_share_path, 'mixxx', 'skins'), skin_files) + vamp_plugin = env.Install( + os.path.join(unix_lib_path, 'mixxx', 'plugins', 'vamp'), + libmixxxminimal_vamp_plugin) + + soundsource_plugins = env.Install( + os.path.join(unix_lib_path, 'mixxx', 'plugins', 'soundsource'), + soundsource_plugin_files) + controllermappings = env.Install(os.path.join(unix_share_path, 'mixxx', 'controllers'), controllermappings_files) + translations = env.Install(os.path.join(unix_share_path, 'mixxx', 'translations'), translation_files) + keyboardmappings = env.Install(os.path.join(unix_share_path, 'mixxx', 'keyboard'), keyboardmappings_files) + if int(flags['ladspa']): + ladspapresets = env.Install( + os.path.join(unix_share_path, 'mixxx', 'ladspa_presets'), ladspapresets_files) + dotdesktop = env.Install(os.path.join(unix_share_path, 'applications'), dotdesktop_files) + docs = env.Install(os.path.join(unix_share_path, 'doc', 'mixxx'), docs_files) + icon = env.Install(os.path.join(unix_share_path, 'pixmaps'), icon_files) + promotracks = env.Install(os.path.join(unix_share_path, 'mixxx', 'promo'), promotracks_files) + + #Makes each of those Install builders get fired off when you run "scons install" :) + env.Alias('install', binary) + env.Alias('install', resource) + env.Alias('install', skins) + env.Alias('install', soundsource_plugins) + env.Alias('install', controllermappings) + env.Alias('install', translations) + env.Alias('install', keyboardmappings) + if int(flags['ladspa']): + env.Alias('install', ladspapresets) + env.Alias('install', docs) + env.Alias('install', dotdesktop) + env.Alias('install', icon) + env.Alias('install', promotracks) + env.Alias('install', vamp_plugin) + + #Delete the old Mixxx installation (because SCONS won't overwrite it) + #if 'install' in COMMAND_LINE_TARGETS: + #os.system('scons -c install') + #Delete(unix_share_path + "/mixxx/skins") + #print "Copying skins..." + #env.Command(unix_share_path + "/mixxx/skins", skin_files, Copy("$TARGET", "$SOURCE"), source_scanner = DirScanner) + #Copy(unix_share_path + "/.ixxx/skins", skin_files) + #Delete(unix_bin_path + "mixxx") + + #Delete(unix_share_path + "/mixxx/controllers") + #Delete(unix_share_path + "/mixxx/keyboard") + +#Build the Mixxx.app bundle +if build.platform_is_osx and 'bundle' in COMMAND_LINE_TARGETS: + #Mixxx build variables + VOLNAME="Mixxx" #tmp tmp tmp, it's unclean to pass this into build_dmg this way. perhaps pass it in the env? + ARCH = 'ppc' if build.machine in ['powerpc', 'powerpc64'] else 'macintel' + ARCH += ("64" if build.machine_is_64bit else "32") + + DMG_ICON="#res/osx/VolumeIcon.icns" + + # this is a BIG HACK to support Qt's plugins (since Qt *requires* that + # it's plugins be in specific subdirectories, which OS X doesn't really + # play nice with) + qt_plugins = ([("iconengines", e) for e in ["libqsvgicon.dylib"]] + + [("imageformats", e) for e in ["libqgif.dylib", "libqjpeg.dylib", "libqsvg.dylib"]] + + [("sqldrivers", e) for e in ["libqsqlite.dylib"]] + + [("accessible", e) for e in ["libqtaccessiblewidgets.dylib"]]) + #Left out libqmng and libqtiff to save space. + + # Concatenate the SoundSource plugins to our list of plugins (converting + # from SCons File nodes to strings) + for x in soundsource_plugins: + plugins.append(x.get_abspath()) + + for x in mixxxminimal_plugins: + plugins.append(x.get_abspath()) + + resource_map = {} + translation_files = Glob('#res/translations/*.qm') + for tfile in translation_files: + resource_map[str(tfile)] = 'translations' + + qtdir = build.env['QTDIR'] + qt_frameworks = depends.Qt.find_framework_path(qtdir) + if not qt_frameworks: + raise Exception('Could not find frameworks in Qt directory: %s' % qtdir) + #qt_menu.nib for Cocoa Qt 4.7+ + menu_nib = os.path.join(qt_frameworks, 'QtGui.framework', + 'Resources', 'qt_menu.nib') + otool_local_paths = [os.path.expanduser("~/Library/Frameworks"), + qt_frameworks, + "/Library/Frameworks", + "/Network/Library/Frameworks", + "/usr/local/lib", + "/opt/local/lib", + "/sw/local/lib"] + otool_system_paths = ["/System/Library/Frameworks", + "/Network/Library/Frameworks", + "/usr/lib"] + mixxx_osxlib_path = SCons.ARGUMENTS.get('osxlib', None) + if mixxx_osxlib_path: + otool_local_paths = [mixxx_osxlib_path,] + otool_local_paths + + qtplugindir = SCons.ARGUMENTS.get('qtplugindir', None) + if not qtplugindir: + #qtplugindir = '/Developer/Applications/Qt/' + qtplugindir = qtdir + sources = [mixxx_bin, + '#res/osx/application.icns', + Dir('#res/skins/'), + File('#res/schema.xml'), + Dir('#res/controllers/'), + translation_files, + Dir('#res/keyboard/'), + Dir('#res/ladspa_presets'), + Dir('#res/doc/'), + Dir('#res/promo/'), + Dir(menu_nib), + File("#README"), + File("#LICENSE")] + bundle = env.App( + "Mixxx", + sources, + PLUGINS=plugins, ##XXX test what happens if we don't pass any plugins + #Qt plugins ((Qt *NEEDS* its plugins in specific locations or it refuses to find them, however this is clearly awkward to write out like this.. maybe)) + QT_HACK = [(p_tgt_dir, os.path.join(qtplugindir, "plugins", p_tgt_dir, p)) for p_tgt_dir, p in qt_plugins], #sigh :( + STRIP=build.build_is_release, + APP_RESOURCES_MAP=resource_map, + IDENTIFIER="org.mixxx.mixxx", + DISPLAY_NAME="Mixxx", + VERSION=mixxx_version, + SHORT_VERSION=mixxx_version, + COPYRIGHT="Copyright © 2011-2013 Mixxx Development Team", #FIXME: datetime.year() + # WARNING(rjryan): If you change this, you must also change it + # in the build/osx/product_definition.plist. + MINIMUM_OSX_VERSION="10.6.0", + CATEGORY="public.app-category.music", + OTOOL_LOCAL_PATHS=otool_local_paths, + OTOOL_SYSTEM_PATHS=otool_system_paths, + FOR_APP_STORE=True, + ) + #env.Default(mixxx_bin) #todo: make the Default() just the program itself *globally* (not just for OS X); bundle should be a separate target + env.Alias('bundle', bundle) + + codesign_installer_identity = SCons.ARGUMENTS.get('osx_codesign_installer_identity', None) + codesign_application_identity = SCons.ARGUMENTS.get('osx_codesign_application_identity', None) + codesign_keychain = SCons.ARGUMENTS.get('osx_codesign_keychain', None) + codesign_keychain_password = SCons.ARGUMENTS.get('osx_codesign_keychain_password', None) + codesign_entitlements = SCons.ARGUMENTS.get('osx_codesign_entitlements', None) + # CodeSign needs to take sources for it source so that there is an input + # that changse. Otherwise SCons will think the CodeSign target is up to + # date and not run it. + codesign = env.CodeSign( + 'Mixxx', + sources, + CODESIGN_INSTALLER_IDENTITY=codesign_installer_identity, + CODESIGN_APPLICATION_IDENTITY=codesign_application_identity, + CODESIGN_KEYCHAIN=codesign_keychain, + CODESIGN_KEYCHAIN_PASSWORD=codesign_keychain_password, + CODESIGN_ENTITLEMENTS=codesign_entitlements) + env.Alias('sign', codesign) + + package_name = 'mixxx' + package_version = osx_construct_version(build, mixxx_version, branch_name, vcs_revision) + dmg_name = '%s-%s-%s' % (package_name, package_version, ARCH) + dmg = env.Dmg(dmg_name, [bundle, ] + docs_files, VOLNAME=VOLNAME, ICON = DMG_ICON) + env.Alias('package', dmg) + +if build.platform_is_windows: + base_dist_dir = '#' + dist_dir + skins = env.Install(os.path.join(base_dist_dir, "skins"), skin_files) + resource = env.Install(base_dist_dir+"/", resource_files) + controllermappings = env.Install(os.path.join(base_dist_dir, "controllers"), controllermappings_files) + translations = env.Install(os.path.join(base_dist_dir, "translations"), translation_files) + keyboardmappings = env.Install(os.path.join(base_dist_dir, "keyboard"), keyboardmappings_files) + if int(flags['ladspa']): + ladspapresets = env.Install(os.path.join(base_dist_dir, "ladspa_presets"), ladspapresets_files) + docs = env.Install(os.path.join(base_dist_dir, "doc/"), docs_files) + promotracks = env.Install(os.path.join(base_dist_dir, "promo/"), promotracks_files) + #icon = env.Install(base_dist_dir+"", icon_files) + dlls = env.Install(base_dist_dir+"/", dll_files) + soundsource_plugins = env.Install(os.path.join(base_dist_dir, "plugins", "soundsource/"), + soundsource_plugin_files) + vamp_plugins = env.Install(os.path.join(base_dist_dir, "plugins", "vamp/"), + libmixxxminimal_vamp_plugin) + binary = env.Install(base_dist_dir+"/", binary_files) + + #Always trigger these install builders when compiling on Windows + env.Alias('mixxx', skins) + env.Alias('mixxx', resource) + env.Alias('mixxx', controllermappings) + env.Alias('mixxx', translations) + env.Alias('mixxx', keyboardmappings) + if int(flags['ladspa']): + env.Alias('mixxx', ladspapresets) + env.Alias('mixxx', promotracks) + env.Alias('mixxx', docs) + env.Alias('mixxx', dlls) + env.Alias('mixxx', soundsource_plugins) + env.Alias('mixxx', vamp_plugins) + #env.Alias('mixxx', icon) + env.Alias('mixxx', binary) + + # QSQLite DLL + if 'sqldll_files' in locals(): + sql_dlls = env.Install(os.path.join(base_dist_dir, "sqldrivers"), sqldll_files) + env.Alias('mixxx', sql_dlls) + +def win32_find_program_via_registry(program_name): + # Windows registry access to find where program is installed + import _winreg + hklm = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) + program_location_handle = None + try: + program_location_handle = _winreg.OpenKey(hklm, "SOFTWARE\\"+program_name, 0, _winreg.KEY_READ) + except WindowsError: + program_location_handle = None + + if not program_location_handle: + try: + program_location_handle = _winreg.OpenKey(hklm, "SOFTWARE\\Wow6432Node\\"+program_name, 0, _winreg.KEY_READ) + except WindowsError: + program_location_handle = None + + program_location = _winreg.QueryValue(program_location_handle, None) + if not program_location: + try: + program_location_tuple = _winreg.QueryValueEx(program_location_handle, "Path") + program_location = program_location_tuple[0] + except WindowsError: + program_location_handle = None + + _winreg.CloseKey(hklm) + return program_location + +def BuildRelease(target, source, env): + print + print "==== Mixxx Post-Build Checks ====" + print + print "You have built version %s" % mixxx_version + print + if int(flags['msvcdebug']): + print "YOU ARE ABOUT TO PACKAGE A DEBUG BUILD!!" + print + print "Binary has size ", + if build.platform_is_windows: + os.system('for %I in ('+dist_dir+'\mixxx.exe) do @echo %~zI') + else: + os.system('ls -lh '+dist_dir+'/mixxx.exe | cut -d \' \' -f 5') + print + print "Installer file ", + package_name = 'mixxx' + + package_version = windows_construct_version( + build, mixxx_version, branch_name, vcs_revision) + arch = "x64" if build.machine_is_64bit else "x86" + exe_name = '%s-%s-%s.exe' % (package_name, package_version, arch) + print exe_name + print + print "Top line of README, check version:" + if build.platform_is_windows: + os.system('for /l %l in (1,1,1) do @for /f "tokens=1,2* delims=:" %a in (\'findstr /n /r "^" README ^| findstr /r "^%l:"\') do @echo %b') + else: + os.system('head -n 1 README') + print + print "Top 2 lines of LICENSE, check version and copyright dates:" + if build.platform_is_windows: + os.system('for /l %l in (1,1,2) do @for /f "tokens=1,2* delims=:" %a in (\'findstr /n /r "^" LICENSE ^| findstr /r "^%l:"\') do @echo %b') + else: + os.system('head -n 2 LICENSE') + print + #if (raw_input("Go ahead and build installer (yes/[no])? ") == "yes"): + if True: + if build.toolchain_is_msvs: + redist_file = 'vcredist_%s.exe' % arch + print "Searching for the Visual C++ DLL installer package",redist_file + + # First check one level above the winlib directory + redist_path = '%s' % os.path.join(os.path.dirname(mixxx_winlib_path), redist_file) + print " ",redist_path, + if not os.path.isfile(redist_path): + print "not found" + # If it's not there, look in the MS SDK directory + mssdk_path = util.get_mssdk_path() + #print " Detected MS SDK path:", mssdk_path + redist_path = '%s' % os.path.join(mssdk_path,'Redist','VC',redist_file) + print " ",redist_path, + if not os.path.isfile(redist_path): + print "not found" + raise Exception('Cannot find the Visual C++ DLL installer.') + + print "Extracting needed files..." + szip_path = None + try: + szip_directory = win32_find_program_via_registry("7-Zip") + szip_path = '%s' % os.path.join(szip_directory, "7z.exe") + except Exception, e: + pass + if szip_path is None: + print "Cannot find 7-Zip. Do you have it installed?" + raise Exception('Cannot find 7-Zip. Do you have it installed?') + else: + output_path = '%s' % os.path.join(mixxx_winlib_path,'VC_redist') + args = [szip_path,"x","-y","-ir!vc_red.*","-ir!*.msp",redist_path,"-o"+output_path] + print "Executing:", ' '.join(args) + proc = subprocess.Popen(args) + data, err = proc.communicate() + rv = proc.wait() + if rv: + raise Exception('There was a problem extracting the installer files. See above for details.') + print "Now building installation package..." + command_flag = None + nsis_path = None + if not build.crosscompile and build.platform_is_windows: + nsis_directory = win32_find_program_via_registry("NSIS") + nsis_path = '"%s"' % os.path.join(nsis_directory, "makensis.exe") + command_flag = '/' + elif build.crosscompile and build.platform_is_windows: + nsis_path = 'makensis' + command_flag = '-' + + if not nsis_path: + print "Cannot find NSIS. Do you have it installed?" + else: + # Call the NSIS build + buildwin64 = "/Dx64=1" if build.machine_is_64bit else '' + command = '%(path)s /DPACKAGE_NAME=%(package_name)s /DPRODUCT_VERSION=%(version)s /DQTDIR=%(qtpath)s /DWINLIB_PATH=%(winlibpath)s %(64bit)s build\\nsis\\Mixxx.nsi' % \ + {'path': nsis_path, + 'package_name': exe_name, + 'version': mixxx_version, + 'qtpath': os.environ['QTDIR'], + 'winlibpath': mixxx_winlib_path, + '64bit': buildwin64} + print "Using command: " + command + subprocess.check_call(command) + else: + print "Aborted building installer" + +# Do release things +versionbld = Builder(action = BuildRelease, suffix = '.foo', src_suffix = '.bar') +env.Append(BUILDERS = {'BuildRelease' : versionbld}) + +if 'makerelease' in COMMAND_LINE_TARGETS: + makerelease = env.BuildRelease('', binary_files) + env.Alias('makerelease', makerelease) + +def ubuntu_append_changelog(debian_dir, + package_name, package_version, + description, + distro='karmic', + urgency='low', + author="Mixxx Buildbot <builds@mixxx.org>"): + now_formatted = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()) + new_entry = [ + "%s (%s) %s; urgency=%s" % (package_name, package_version, distro, urgency), + "", + description, + "", + " -- %s %s" % (author, now_formatted), + "", + ] + lines = [] + with open(os.path.join(debian_dir, 'changelog'), 'r') as changelog: + lines = list(changelog) + with open(os.path.join(debian_dir, 'changelog'), 'w') as changelog: + changelog.writelines(["%s\n" % x for x in new_entry]) + changelog.writelines(lines) + +def ubuntu_cleanup(): + os.system('rm -rf ubuntu') + os.mkdir('ubuntu') + +# Build the Ubuntu package +def BuildUbuntuPackage(target, source, env): + global mixxx_version + print + print "==== Mixxx Post-Build Checks ====" + print + print "You have built version ", mixxx_version + print + print + print "Top line of README, check version:" + os.system('head -n 1 README') + print + print "Top 2 lines of LICENSE, check version and copyright dates:" + os.system('head -n 2 LICENSE') + print + print "Top line of debian/ubuntu changelog, check version:" + os.system('head -n 1 build/debian/changelog') + print + + print "Now building DEB package..." + print + + arch = 'amd64' if build.machine_is_64bit else 'i386' + + package_target = ARGUMENTS.get('package', None) + ubuntu_distros = ARGUMENTS.get('ubuntu_dist', None) + if ubuntu_distros is None: + print "You did not specify an Ubuntu distribution to target. Specify one with the ubuntu_dist flag." + # TODO(XXX) default to their current distro? the .pbuilderrc does this + return + ubuntu_version = ARGUMENTS.get('ubuntu_version', '0ubuntu1') + ubuntu_ppa = ARGUMENTS.get('ubuntu_ppa', None) + + ubuntu_distros = ubuntu_distros.split(',') + + # Big hack for PPA upload. We need LP to believe that our original + # package version is always changing otherwise it will reject our orig + # source tarball. + if ubuntu_ppa is not None: + mixxx_version = '%s-%s%s' % (mixxx_version, vcs_name, vcs_revision) + + # Destroy ubuntu/ and create it + ubuntu_cleanup() + + package_name = 'mixxx' + + # directory and original tarball need to have the upstream-release + # version, NOT the package version. For example: + # upstream version: 1.10.0-beta1 + # package version: 1.10.0-beta1-0ubuntu1~bzr2206 + # directory name: mixxx-1.10.0-beta1 + # original tarball: mixxx_1.10.0-beta1.orig.tar.gz + + mixxx_dir = '%s-%s' % (package_name, mixxx_version) + # The underscore is super important here to make the deb package work + mixxx_tarball = "%s_%s.orig.tar.gz" % (package_name, mixxx_version) + + build_dir = os.path.join('ubuntu', mixxx_dir) + + if os.path.exists(build_dir): + print "* Cleaning up %s (cwd: %s)" % (build_dir, os.getcwd()) + print + os.system('rm -rf %s' % build_dir) # be careful. + + # TODO: make a get flags arg to accept a revision which can override this and checkout of a specific SVN rev for the package + + # Export the source folder + print "* Exporting source folder from current workspace (%s rev: %s)" % (vcs_name, + vcs_revision) + print + util.export_source('.', build_dir) + + # Copy a patch to be included in the exported build sources (this can also be something like src/SConscript, /build/debian/rules) + if os.path.exists('post-export-patch'): + print "* Applying post export patch" + print + os.system('cp --dereference -r post-export-patch/* %s' % build_dir) + + # Write a build.h to the exported directory. Later code looks for a + # build.h in the mixxx/ directory and moves it to build.build_dir/ + # instead of generating. + util.write_build_header(os.path.join(build_dir, 'build.h')) + + os.chdir('ubuntu') + + # Tar the source code + print "* Tarring source directory to '%s' ... (this can take a couple minutes)" % os.path.join(os.getcwd(), mixxx_tarball) + print + os.system('rm -f "%s"' % mixxx_tarball) #Remove old tarball + os.system('tar --exclude build/debian --exclude=debian --exclude=debian/* -czf "%s" %s' % (mixxx_tarball, mixxx_dir)) + + os.chdir(mixxx_dir) + # Copy the debian folder from /build/debian to exported source folder root + print "* Copying Debian build directory from build/debian to debian (cwd: %s)" % os.getcwd() + print + os.system('cp -r build/debian .') + + for ubuntu_distro in ubuntu_distros: + # if a control.$distro file exists, use it + if os.path.exists('debian/control.%s' % ubuntu_distro): + os.system('cp debian/control.%s debian/control' % ubuntu_distro) + # TODO(rryan) currently can only have version 1 within a distro + ubuntu_distro_version = '%s~%s1' % (ubuntu_version, ubuntu_distro) + package_version = ubuntu_construct_version(build, mixxx_version, + branch_name, vcs_revision, + ubuntu_distro_version) + + # Add a changelog record for this package + if build.build_is_debug: + description = " * Experimental build of branch '%s' at Bazaar revision %s" % (branch_name, vcs_revision) + ubuntu_append_changelog('debian', package_name, package_version, + description, distro=ubuntu_distro) + else: + description = " * New upstream release." + ubuntu_append_changelog('debian', package_name, package_version, + description, + distro=ubuntu_distro, + author="RJ Ryan <rryan@mixxx.org>") + + # Run pbuilder + print "* Starting pbuilder ... (cwd: %s)" % os.getcwd() + print + + command = ["ARCH=%s" % arch, + "DIST=%s" % ubuntu_distro] + + if package_target == 'source': + # TODO(rryan) we have to figure out the key-signing situation + # here. + command.extend(['debuild', '-S', '-sa']) + else: + command.extend(['pdebuild']) + result = os.system(' '.join(command)) + + if package_target == 'source': + if result == 0: + # TODO(rryan) check it actually succeeded + print "* Done! Signed source package is in ubuntu/" + print + else: + print "* Build failed." + print + else: + result_path = "/var/cache/pbuilder/%s-%s/result/" % (ubuntu_distro, arch) + result_filename = "%s_%s_%s.deb" % (package_name, package_version, arch) + result_file = os.path.join(result_path, result_filename) + # Since we might build for multiple distros we need to + # insert the distro name into the filename. + dest_filename = "%s_%s_%s_%s.deb" % (package_name, package_version, ubuntu_distro, arch) + # ubuntu/ is one folder up + dest_file = os.path.join('..', dest_filename) + + if result == 0 and os.path.exists(result_file): + print "Done! Package and tarballs are in %s" % result_path + print "* Found package at '%s'. Copying to ubuntu/" % result_filename + print + shutil.copyfile(result_file, dest_file) + else: + print "* Build failed." + print + + # print "Signing the .deb changes file..." + # os.system('sudo debsign /var/cache/pbuilder/result/*.changes') + + if ubuntu_ppa is not None: + # dput this changes file to the PPA + dput_command = 'dput %s ../%s_%s_source.changes' % (ubuntu_ppa, package_name, package_version) + print "* Uploading package for", ubuntu_distro, "to launchpad:", dput_command + os.system(dput_command) + + # Return back to the starting directory, otherwise you'll get a .sconsign.dblite error! + os.chdir('../..') + print "* Returning to starting working directory ... (cwd: " + os.getcwd() + ")" + print + +#Build the Ubuntu package if "makeubuntu" was passed as an argument +versiondebbld = Builder(action = BuildUbuntuPackage) #, suffix = '.foo', src_suffix = '.bar') +env.Append(BUILDERS = {'BuildUbuntuPackage' : versiondebbld}) + +if 'makeubuntu' in COMMAND_LINE_TARGETS: + makeubuntu = env.BuildUbuntuPackage("blah", "defs_version.h" ) #(binary_files) + env.Alias('makeubuntu', makeubuntu) |