From 74dda188dce4a19201fc8b45998967de6d771aea Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Mon, 25 May 2015 15:17:18 +0100 Subject: [PATCH] Reintroduced accidentally removed functions #4695 --- ext/toolchain/commands1.py | 33 +- ext/toolchain/fuckfuck.py | 2000 +++++++++++++++++++++++++++++++++++ ext/toolchain/shitindent.py | 31 + 3 files changed, 2059 insertions(+), 5 deletions(-) create mode 100644 ext/toolchain/fuckfuck.py create mode 100644 ext/toolchain/shitindent.py diff --git a/ext/toolchain/commands1.py b/ext/toolchain/commands1.py index f8f14854..32716b12 100644 --- a/ext/toolchain/commands1.py +++ b/ext/toolchain/commands1.py @@ -1439,14 +1439,37 @@ class InternalCommands: self.getGitBranchName(), self.getGitRevision()) return re.sub(pattern, replace, self.dist_name(type)) - def getDebianArch(self): - if os.uname()[4][:3] == 'arm': - return 'armhf' + def getDebianArch(self): + if os.uname()[4][:3] == 'arm': + return 'armhf' + # os_bits should be loaded with '32bit' or '64bit' + import platform + (os_bits, other) = platform.architecture() + + # get platform based on current platform + if os_bits == '32bit': + return 'i386' + elif os_bits == '64bit': + return 'amd64' + else: + raise Exception("unknown os bits: " + os_bits) - if os.uname()[4][:3] == 'arm': - return 'Linux-armv6l' + def getLinuxPlatform(self): + if os.uname()[4][:3] == 'arm': + return 'Linux-armv6l' + # os_bits should be loaded with '32bit' or '64bit' + import platform + (os_bits, other) = platform.architecture() + + # get platform based on current platform + if os_bits == '32bit': + return 'Linux-i686' + elif os_bits == '64bit': + return 'Linux-x86_64' + else: + raise Exception("unknown os bits: " + os_bits) def dist_usage(self): print ('Usage: %s package [package-type]\n' diff --git a/ext/toolchain/fuckfuck.py b/ext/toolchain/fuckfuck.py new file mode 100644 index 00000000..4dcb6def --- /dev/null +++ b/ext/toolchain/fuckfuck.py @@ -0,0 +1,2000 @@ +# synergy -- mouse and keyboard sharing utility +# Copyright (C) 2012 Synergy Si Ltd. +# Copyright (C) 2009 Nick Bolton +# +# This package is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# found in the file LICENSE that should have accompanied this file. +# +# This package is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# TODO: split this file up, it's too long! + +import sys, os, ConfigParser, shutil, re, ftputil, zipfile, glob, commands +from generators import VisualStudioGenerator, EclipseGenerator, XcodeGenerator, MakefilesGenerator +from getopt import gnu_getopt + +if sys.version_info >= (2, 4): + import subprocess + +class Toolchain: + + # minimum required version. + # 2.6 needed for ZipFile.extractall. + # do not change to 2.7, as the build machines are still at 2.6 + # and are a massive pain in the ass to upgrade. + requiredMajor = 2 + requiredMinor = 6 + + # options used by all commands + globalOptions = 'v' + globalOptionsLong = ['no-prompts', 'verbose', 'skip-gui', 'skip-core'] + + # list of valid commands as keys. the values are optarg strings, but most + # are None for now (this is mainly for extensibility) + cmd_opt_dict = { + 'about' : ['', []], + 'setup' : ['g:', ['generator=']], + 'configure' : ['g:dr', ['generator=', 'debug', 'release', 'mac-sdk=', 'mac-identity=']], + 'build' : ['dr', ['debug', 'release']], + 'clean' : ['dr', ['debug', 'release']], + 'update' : ['', []], + 'install' : ['', []], + 'doxygen' : ['', []], + 'dist' : ['', ['vcredist-dir=', 'qt-dir=']], + 'distftp' : ['', ['host=', 'user=', 'pass=', 'dir=']], + 'kill' : ['', []], + 'usage' : ['', []], + 'revision' : ['', []], + 'reformat' : ['', []], + 'open' : ['', []], + 'genlist' : ['', []], + 'reset' : ['', []], + 'signwin' : ['', ['pfx=', 'pwd=', 'dist']], + 'signmac' : ['', []] + } + + # aliases to valid commands + cmd_alias_dict = { + 'info' : 'about', + 'help' : 'usage', + 'package' : 'dist', + 'docs' : 'doxygen', + 'make' : 'build', + 'cmake' : 'configure', + } + + def complete_command(self, arg): + completions = [] + + for cmd, optarg in self.cmd_opt_dict.iteritems(): + # if command was matched fully, return only this, so that + # if `dist` is typed, it will return only `dist` and not + # `dist` and `distftp` for example. + if cmd == arg: + return [cmd,] + if cmd.startswith(arg): + completions.append(cmd) + + for alias, cmd in self.cmd_alias_dict.iteritems(): + # don't know if this will work just like above, but it's + # probably worth adding. + if alias == arg: + return [alias,] + if alias.startswith(arg): + completions.append(alias) + + return completions + + def start_cmd(self, argv): + + cmd_arg = '' + if len(argv) > 1: + cmd_arg = argv[1] + + # change common help args to help command + if cmd_arg in ('--help', '-h', '--usage', '-u', '/?'): + cmd_arg = 'usage' + + completions = self.complete_command(cmd_arg) + + if cmd_arg and len(completions) > 0: + + if len(completions) == 1: + + # get the only completion (since in this case we have 1) + cmd = completions[0] + + # build up the first part of the map (for illustrative purposes) + cmd_map = list() + if cmd_arg != cmd: + cmd_map.append(cmd_arg) + cmd_map.append(cmd) + + # map an alias to the command, and build up the map + if cmd in self.cmd_alias_dict.keys(): + alias = cmd + if cmd_arg == cmd: + cmd_map.append(alias) + cmd = self.cmd_alias_dict[cmd] + cmd_map.append(cmd) + + # show command map to avoid confusion + if len(cmd_map) != 0: + print 'Mapping command: %s' % ' -> '.join(cmd_map) + + self.run_cmd(cmd, argv[2:]) + + return 0 + + else: + print ( + 'Command `%s` too ambiguous, ' + 'could mean any of: %s' + ) % (cmd_arg, ', '.join(completions)) + else: + + if len(argv) == 1: + print 'No command specified, showing usage.\n' + else: + print 'Command not recognised: %s\n' % cmd_arg + + self.run_cmd('usage') + + # generic error code if not returned sooner + return 1 + + def run_cmd(self, cmd, argv = []): + + verbose = False + try: + options_pair = self.cmd_opt_dict[cmd] + + options = self.globalOptions + options_pair[0] + + options_long = [] + options_long.extend(self.globalOptionsLong) + options_long.extend(options_pair[1]) + + opts, args = gnu_getopt(argv, options, options_long) + + for o, a in opts: + if o in ('-v', '--verbose'): + verbose = True + + # pass args and optarg data to command handler, which figures out + # how to handle the arguments + handler = CommandHandler(argv, opts, args, verbose) + + # use reflection to get the function pointer + cmd_func = getattr(handler, cmd) + + cmd_func() + except: + if not verbose: + # print friendly error for users + sys.stderr.write('Error: ' + sys.exc_info()[1].__str__() + '\n') + sys.exit(1) + else: + # if user wants to be verbose let python do it's thing + raise + + def run(self, argv): + if sys.version_info < (self.requiredMajor, self.requiredMinor): + print ('Python version must be at least ' + + str(self.requiredMajor) + '.' + str(self.requiredMinor) + ', but is ' + + str(sys.version_info[0]) + '.' + str(sys.version_info[1])) + sys.exit(1) + + try: + self.start_cmd(argv) + except KeyboardInterrupt: + print '\n\nUser aborted, exiting.' + +class InternalCommands: + + project = 'synergy' + setup_version = 5 # increment to force setup/config + website_url = 'http://synergy-project.org/' + + this_cmd = 'hm' + cmake_cmd = 'cmake' + qmake_cmd = 'qmake' + make_cmd = 'make' + xcodebuild_cmd = 'xcodebuild' + w32_make_cmd = 'mingw32-make' + w32_qt_version = '4.6.2' + defaultTarget = 'release' + + cmake_dir = 'res' + gui_dir = 'src/gui' + doc_dir = 'doc' + extDir = 'ext' + + sln_filename = '%s.sln' % project + xcodeproj_filename = '%s.xcodeproj' % project + configDir = 'build' + configFilename = '%s/%s.cfg' % (configDir, this_cmd) + qtpro_filename = 'gui.pro' + doxygen_filename = 'doxygen.cfg' + + cmake_url = 'http://www.cmake.org/cmake/resources/software.html' + + # try_chdir(...) and restore_chdir() will use this + prevdir = '' + + # by default, no index specified as arg + generator_id = None + + # by default, prompt user for input + no_prompts = False + + # by default, compile the core + enableMakeCore = True + + # by default, compile the gui + enableMakeGui = True + + # by default, unknown + macSdk = None + + # by default, unknown + macIdentity = None + + # gtest dir with version number + gtestDir = 'gtest-1.6.0' + + # gmock dir with version number + gmockDir = 'gmock-1.6.0' + + win32_generators = { + 1 : VisualStudioGenerator('10'), + 2 : VisualStudioGenerator('10 Win64'), + 3 : VisualStudioGenerator('9 2008'), + 4 : VisualStudioGenerator('9 2008 Win64'), + 5 : VisualStudioGenerator('8 2005'), + 6 : VisualStudioGenerator('8 2005 Win64') + } + + unix_generators = { + 1 : MakefilesGenerator(), + 2 : EclipseGenerator(), + } + + darwin_generators = { + 1 : MakefilesGenerator(), + 2 : XcodeGenerator(), + 3 : EclipseGenerator(), + } + + def getBuildDir(self, target=''): + return self.getGenerator().getBuildDir(target) + + def getBinDir(self, target=''): + return self.getGenerator().getBinDir(target) + + def sln_filepath(self): + return '%s\%s' % (self.getBuildDir(), self.sln_filename) + + def xcodeproj_filepath(self, target=''): + return '%s/%s' % (self.getBuildDir(target), self.xcodeproj_filename) + + def usage(self): + app = sys.argv[0] + print ('Usage: %s [-g |-v|--no-prompts|]\n' + '\n' + 'Replace [command] with one of:\n' + ' about Show information about this script\n' + ' setup Runs the initial setup for this script\n' + ' conf Runs cmake (generates project files)\n' + ' open Attempts to open the generated project file\n' + ' build Builds using the platform build chain\n' + ' clean Cleans using the platform build chain\n' + ' kill Kills all synergy processes (run as admin)\n' + ' update Updates the source code from repository\n' + ' revision Display the current source code revision\n' + ' package Create a distribution package (e.g. tar.gz)\n' + ' install Installs the program\n' + ' doxygen Builds doxygen documentation\n' + ' reformat Reformat .cpp and .h files using AStyle\n' + ' genlist Shows the list of available platform generators\n' + ' usage Shows the help screen\n' + '\n' + 'Example: %s build -g 3' + ) % (app, app) + + def configureAll(self, targets, extraArgs=''): + + # if no mode specified, use default + if len(targets) == 0: + targets += [self.defaultTarget,] + + for target in targets: + self.configure(target) + + def checkGTest(self): + dir = self.extDir + '/' + self.gtestDir + if (os.path.isdir(dir)): + return + + zipFilename = dir + '.zip' + if (not os.path.exists(zipFilename)): + raise Exception('GTest zip not found at: ' + zipFilename) + + if not os.path.exists(dir): + os.mkdir(dir) + + zip = zipfile.ZipFile(zipFilename) + self.zipExtractAll(zip, dir) + + def checkGMock(self): + dir = self.extDir + '/' + self.gmockDir + if (os.path.isdir(dir)): + return + + zipFilename = dir + '.zip' + if (not os.path.exists(zipFilename)): + raise Exception('GMock zip not found at: ' + zipFilename) + + if not os.path.exists(dir): + os.mkdir(dir) + + zip = zipfile.ZipFile(zipFilename) + self.zipExtractAll(zip, dir) + + # ZipFile.extractall() is buggy in 2.6.1 + # http://bugs.python.org/issue4710 + def zipExtractAll(self, z, dir): + if not dir.endswith("/"): + dir += "/" + + for f in z.namelist(): + if f.endswith("/"): + os.makedirs(dir + f) + else: + z.extract(f, dir) + + def configure(self, target='', extraArgs=''): + + # ensure latest setup and do not ask config for generator (only fall + # back to prompt if not specified as arg) + self.ensure_setup_latest() + + if sys.platform == "darwin": + config = self.getConfig() + + if self.macSdk: + config.set('hm', 'macSdk', self.macSdk) + elif config.has_option("hm", "macSdk"): + self.macSdk = config.get('hm', 'macSdk') + + if self.macIdentity: + config.set('hm', 'macIdentity', self.macIdentity) + elif config.has_option("hm", "macIdentity"): + self.macIdentity = config.get('hm', 'macIdentity') + + self.write_config(config) + + if not self.macSdk: + raise Exception("Arg missing: --mac-sdk "); + + if not self.macIdentity: + raise Exception("Arg missing: --mac-identity "); + + sdkDir = self.getMacSdkDir() + if not os.path.exists(sdkDir): + raise Exception("Mac SDK not found at: " + sdkDir) + + os.environ["MACOSX_DEPLOYMENT_TARGET"] = self.macSdk + + # default is release + if target == '': + print 'Defaulting target to: ' + self.defaultTarget + target = self.defaultTarget + + # allow user to skip core compile + if self.enableMakeCore: + self.configureCore(target, extraArgs) + + # allow user to skip gui compile + if self.enableMakeGui: + self.configureGui(target, extraArgs) + + self.setConfRun(target) + + def configureCore(self, target="", extraArgs=""): + + # ensure that we have access to cmake + _cmake_cmd = self.persist_cmake() + + # now that we know we've got the latest setup, we can ask the config + # file for the generator (but again, we only fall back to this if not + # specified as arg). + generator = self.getGenerator() + + if generator != self.findGeneratorFromConfig(): + print('Generator changed, running setup.') + self.setup(target) + + cmake_args = '' + if generator.cmakeName != '': + cmake_args += ' -G "' + generator.cmakeName + '"' + + # for makefiles always specify a build type (debug, release, etc) + if generator.cmakeName.find('Unix Makefiles') != -1: + cmake_args += ' -DCMAKE_BUILD_TYPE=' + target.capitalize() + + elif sys.platform == "darwin": + macSdkMatch = re.match("(\d+)\.(\d+)", self.macSdk) + if not macSdkMatch: + raise Exception("unknown osx version: " + self.macSdk) + + sdkDir = self.getMacSdkDir() + cmake_args += " -DCMAKE_OSX_SYSROOT=" + sdkDir + cmake_args += " -DCMAKE_OSX_DEPLOYMENT_TARGET=" + self.macSdk + cmake_args += " -DOSX_TARGET_MAJOR=" + macSdkMatch.group(1) + cmake_args += " -DOSX_TARGET_MINOR=" + macSdkMatch.group(2) + + # if not visual studio, use parent dir + sourceDir = generator.getSourceDir() + + self.checkGTest() + self.checkGMock() + + if extraArgs != '': + cmake_args += ' ' + extraArgs + + cmake_cmd_string = _cmake_cmd + cmake_args + ' ' + sourceDir + + # Run from build dir so we have an out-of-source build. + self.try_chdir(self.getBuildDir(target)) + + print "CMake command: " + cmake_cmd_string + err = os.system(cmake_cmd_string) + + self.restore_chdir() + + if generator.cmakeName.find('Eclipse') != -1: + self.fixCmakeEclipseBug() + + if err != 0: + raise Exception('CMake encountered error: ' + str(err)) + + def configureGui(self, target="", extraArgs=""): + + # make sure we have qmake + self.persist_qmake() + + qmake_cmd_string = self.qmake_cmd + " " + self.qtpro_filename + " -r" + + if sys.platform == "darwin": + + # create makefiles on mac (not xcode). + qmake_cmd_string += " -spec macx-g++" + + (major, minor) = self.getMacVersion() + if major == 10 and minor <= 4: + # 10.4: universal (intel and power pc) + qmake_cmd_string += ' CONFIG+="ppc i386"' + + libs = ( + "-framework ApplicationServices " + "-framework Security " + "-framework cocoa") + + if major == 10 and minor >= 6: + libs += " -framework ServiceManagement" + + qmake_cmd_string += " \"MACX_LIBS=%s\" " % libs + + sdkDir = self.getMacSdkDir() + shortForm = "macosx" + self.macSdk + version = str(major) + "." + str(minor) + + qmake_cmd_string += " QMAKE_MACOSX_DEPLOYMENT_TARGET=" + version + + (qMajor, qMinor, qRev) = self.getQmakeVersion() + if qMajor <= 4: + # 4.6: qmake takes full sdk dir. + qmake_cmd_string += " QMAKE_MAC_SDK=" + sdkDir + else: + # 5.2: now we need to use the .path setting. + qmake_cmd_string += " QMAKE_MAC_SDK=" + shortForm + qmake_cmd_string += " QMAKE_MAC_SDK." + shortForm + ".path=" + sdkDir + + print "QMake command: " + qmake_cmd_string + + # run qmake from the gui dir + self.try_chdir(self.gui_dir) + err = os.system(qmake_cmd_string) + self.restore_chdir() + + if err != 0: + raise Exception('QMake encountered error: ' + str(err)) + + def getQmakeVersion(self): + version = commands.getoutput("qmake --version") + result = re.search('(\d+)\.(\d+)\.(\d)', version) + + if not result: + raise Exception("Could not get qmake version.") + + major = int(result.group(1)) + minor = int(result.group(2)) + rev = int(result.group(3)) + + return (major, minor, rev) + + def getMacSdkDir(self): + sdkName = "macosx" + self.macSdk + + # Ideally we'll use xcrun (which is influenced by $DEVELOPER_DIR), then try a couple + # fallbacks to known paths if xcrun is not available + status, sdkPath = commands.getstatusoutput("xcrun --show-sdk-path --sdk " + sdkName) + if status == 0 and sdkPath: + return sdkPath + + developerDir = os.getenv("DEVELOPER_DIR") + if not developerDir: + developerDir = "/Applications/Xcode.app/Contents/Developer" + + sdkDirName = sdkName.replace("macosx", "MacOSX") + sdkPath = developerDir + "/Platforms/MacOSX.platform/Developer/SDKs/" + sdkDirName + ".sdk" + if os.path.exists(sdkPath): + return sdkPath + + return "/Developer/SDKs/" + sdkDirName + ".sdk" + + # http://tinyurl.com/cs2rxxb + def fixCmakeEclipseBug(self): + print "Fixing CMake Eclipse bugs..." + + file = open('.project', 'r+') + content = file.read() + pattern = re.compile('\s+.+', re.S) + content = pattern.sub('', content) + file.seek(0) + file.write(content) + file.truncate() + file.close() + + def persist_cmake(self): + # even though we're running `cmake --version`, we're only doing this for the 0 return + # code; we don't care about the version, since CMakeLists worrys about this for us. + err = os.system('%s --version' % self.cmake_cmd) + + if err != 0: + # if return code from cmake is not 0, then either something has + # gone terribly wrong with --version, or it genuinely doesn't exist. + print ('Could not find `%s` in system path.\n' + 'Download the latest version from:\n %s') % ( + self.cmake_cmd, self.cmake_url) + raise Exception('Cannot continue without CMake.') + else: + return self.cmake_cmd + + def persist_qt(self): + self.persist_qmake() + + def persist_qmake(self): + # cannot use subprocess on < python 2.4 + if sys.version_info < (2, 4): + return + + try: + p = subprocess.Popen( + [self.qmake_cmd, '--version'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + except: + print >> sys.stderr, 'Error: Could not find qmake.' + if sys.platform == 'win32': # windows devs usually need hints ;) + print ( + 'Suggestions:\n' + '1. Ensure that qmake.exe exists in your system path.\n' + '2. Try to download Qt (check our dev FAQ for links):\n' + ' qt-sdk-win-opensource-2010.02.exe') + raise Exception('Cannot continue without qmake.') + + stdout, stderr = p.communicate() + if p.returncode != 0: + raise Exception('Could not test for cmake: %s' % stderr) + else: + m = re.search('.*Using Qt version (\d+\.\d+\.\d+).*', stdout) + if m: + if sys.platform == 'win32': + ver = m.group(1) + if ver != self.w32_qt_version: # TODO: test properly + print >> sys.stderr, ( + 'Warning: Not using supported Qt version %s' + ' (your version is %s).' + ) % (self.w32_qt_version, ver) + else: + pass # any version should be ok for other platforms + else: + raise Exception('Could not find qmake version.') + + def ensureConfHasRun(self, target, skipConfig): + if self.hasConfRun(target): + print 'Skipping config for target: ' + target + skipConfig = True + + if not skipConfig: + self.configure(target) + + def build(self, targets=[], skipConfig=False): + + # if no mode specified, use default + if len(targets) == 0: + targets += [self.defaultTarget,] + + self.ensure_setup_latest() + + self.loadConfig() + + # allow user to skip core compile + if self.enableMakeCore: + self.makeCore(targets) + + # allow user to skip gui compile + if self.enableMakeGui: + self.makeGui(targets) + + def loadConfig(self): + config = self.getConfig() + + if config.has_option("hm", "macSdk"): + self.macSdk = config.get("hm", "macSdk") + + if config.has_option("hm", "macIdentity"): + self.macIdentity = config.get("hm", "macIdentity") + + def makeCore(self, targets): + + generator = self.getGeneratorFromConfig().cmakeName + + if self.macSdk: + os.environ["MACOSX_DEPLOYMENT_TARGET"] = self.macSdk + + if generator.find('Unix Makefiles') != -1: + for target in targets: + self.runBuildCommand(self.make_cmd, target) + else: + for target in targets: + if generator.startswith('Visual Studio'): + self.run_vcbuild(generator, target, self.sln_filepath()) + elif generator == 'Xcode': + cmd = self.xcodebuild_cmd + ' -configuration ' + target.capitalize() + self.runBuildCommand(cmd, target) + else: + raise Exception('Build command not supported with generator: ' + generator) + + def makeGui(self, targets, args=""): + for target in targets: + + if sys.platform == 'win32': + + gui_make_cmd = self.w32_make_cmd + ' ' + target + args + print 'Make GUI command: ' + gui_make_cmd + + self.try_chdir(self.gui_dir) + err = os.system(gui_make_cmd) + self.restore_chdir() + + if err != 0: + raise Exception(gui_make_cmd + ' failed with error: ' + str(err)) + + elif sys.platform in ['linux2', 'sunos5', 'freebsd7', 'darwin']: + + gui_make_cmd = self.make_cmd + " -w" + args + print 'Make GUI command: ' + gui_make_cmd + + # start with a clean app bundle + targetDir = self.getGenerator().getBinDir(target) + bundleTargetDir = targetDir + '/Synergy.app' + if os.path.exists(bundleTargetDir): + shutil.rmtree(bundleTargetDir) + + binDir = self.getGenerator().binDir + bundleTempDir = binDir + '/Synergy.app' + if os.path.exists(bundleTempDir): + shutil.rmtree(bundleTempDir) + + self.try_chdir(self.gui_dir) + err = os.system(gui_make_cmd) + self.restore_chdir() + + if err != 0: + raise Exception(gui_make_cmd + ' failed with error: ' + str(err)) + + if sys.platform == 'darwin' and not "clean" in args: + self.macPostGuiMake(target) + + self.fixQtFrameworksLayout(target) + else: + raise Exception('Unsupported platform: ' + sys.platform) + + def macPostGuiMake(self, target): + bundle = 'Synergy.app' + binDir = self.getGenerator().binDir + targetDir = self.getGenerator().getBinDir(target) + bundleTempDir = binDir + '/' + bundle + bundleTargetDir = targetDir + '/' + bundle + + if os.path.exists(bundleTempDir): + shutil.move(bundleTempDir, bundleTargetDir) + + if self.enableMakeCore: + # copy core binaries into the bundle, since the gui + # now looks for the binaries in the current app dir. + + bundleBinDir = bundleTargetDir + "/Contents/MacOS/" + shutil.copy(targetDir + "/synergyc", bundleBinDir) + shutil.copy(targetDir + "/synergys", bundleBinDir) + shutil.copy(targetDir + "/syntool", bundleBinDir) + + self.loadConfig() + if not self.macIdentity: + raise Exception("run config with --mac-identity") + + if self.enableMakeGui: + # use qt to copy libs to bundle so no dependencies are needed. do not create a + # dmg at this point, since we need to sign it first, and then create our own + # after signing (so that qt does not affect the signed app bundle). + bin = "macdeployqt Synergy.app -verbose=2" + self.try_chdir(targetDir) + err = os.system(bin) + self.restore_chdir() + print bundleTargetDir + if err != 0: + raise Exception(bin + " failed with error: " + str(err)) + + (qMajor, qMinor, qRev) = self.getQmakeVersion() + if qMajor <= 4: + frameworkRootDir = "/Library/Frameworks" + else: + # TODO: auto-detect, qt can now be installed anywhere. + frameworkRootDir = "/Developer/Qt5.2.1/5.2.1/clang_64/lib" + + target = bundleTargetDir + "/Contents/Frameworks" + + # copy the missing Info.plist files for the frameworks. + for root, dirs, files in os.walk(target): + for dir in dirs: + if dir.startswith("Qt"): + shutil.copy( + frameworkRootDir + "/" + dir + "/Contents/Info.plist", + target + "/" + dir + "/Resources/") + + def symlink(self, source, target): + if not os.path.exists(target): + os.symlink(source, target) + + def move(self, source, target): + if os.path.exists(source): + shutil.move(source, target) + + def fixQtFrameworksLayout(self, target): + # reorganize Qt frameworks layout on Mac 10.9.5 or later + # http://goo.gl/BFnQ8l + # QtCore example: + # QtCore.framework/ + # QtCore -> Versions/Current/QtCore + # Resources -> Versions/Current/Resources + # Versions/ + # Current -> 5 + # 5/ + # QtCore + # Resources/ + # Info.plist + targetDir = self.getGenerator().getBinDir(target) + + target = targetDir + "/Synergy.app/Contents/Frameworks" + (major, minor) = self.getMacVersion() + if major == 10: + if minor >= 9: + for root, dirs, files in os.walk(target): + for dir in dirs: + if dir.startswith("Qt"): + self.try_chdir(target + "/" + dir +"/Versions") + self.symlink("5", "Current") + self.move("../Resources", "5") + self.restore_chdir() + + self.try_chdir(target + "/" + dir) + dot = dir.find('.') + frameworkName = dir[:dot] + self.symlink("Versions/Current/" + frameworkName, frameworkName) + self.symlink("Versions/Current/Resources", "Resources") + self.restore_chdir() + + def signmac(self): + self.loadConfig() + if not self.macIdentity: + raise Exception("run config with --mac-identity") + + self.try_chdir("bin/Release/") + err = os.system( + 'codesign --deep -fs "' + self.macIdentity + '" Synergy.app') + self.restore_chdir() + + if err != 0: + raise Exception("codesign failed with error: " + str(err)) + + def signwin(self, pfx, pwdFile, dist): + generator = self.getGeneratorFromConfig().cmakeName + if not generator.startswith('Visual Studio'): + raise Exception('only windows is supported') + + f = open(pwdFile) + lines = f.readlines() + f.close() + pwd = lines[0] + + if (dist): + self.signFile(pfx, pwd, 'bin/Release', self.dist_name('win')) + else: + self.signFile(pfx, pwd, 'bin/Release', 'synergy.exe') + self.signFile(pfx, pwd, 'bin/Release', 'synergyc.exe') + self.signFile(pfx, pwd, 'bin/Release', 'synergys.exe') + self.signFile(pfx, pwd, 'bin/Release', 'synergyd.exe') + self.signFile(pfx, pwd, 'bin/Release', 'syntool.exe') + self.signFile(pfx, pwd, 'bin/Release', 'synwinhk.dll') + + def signFile(self, pfx, pwd, dir, file): + self.try_chdir(dir) + err = os.system( + 'signtool sign' + ' /f ' + pfx + + ' /p ' + pwd + + ' /t http://timestamp.verisign.com/scripts/timstamp.dll ' + + file) + self.restore_chdir() + + if err != 0: + raise Exception("signtool failed with error: " + str(err)) + + def runBuildCommand(self, cmd, target): + + self.try_chdir(self.getBuildDir(target)) + err = os.system(cmd) + self.restore_chdir() + + if err != 0: + raise Exception(cmd + ' failed: ' + str(err)) + + def clean(self, targets=[]): + + # if no mode specified, use default + if len(targets) == 0: + targets += [self.defaultTarget,] + + # allow user to skip core clean + if self.enableMakeCore: + self.cleanCore(targets) + + # allow user to skip qui clean + if self.enableMakeGui: + self.cleanGui(targets) + + def cleanCore(self, targets): + generator = self.getGeneratorFromConfig().cmakeName + + if generator.startswith('Visual Studio'): + # special case for version 10, use new /target:clean + if generator.startswith('Visual Studio 10'): + for target in targets: + self.run_vcbuild(generator, target, self.sln_filepath(), '/target:clean') + + # any other version of visual studio, use /clean + elif generator.startswith('Visual Studio'): + for target in targets: + self.run_vcbuild(generator, target, self.sln_filepath(), '/clean') + + else: + cmd = '' + if generator == "Unix Makefiles": + print 'Cleaning with GNU Make...' + cmd = self.make_cmd + elif generator == 'Xcode': + print 'Cleaning with Xcode...' + cmd = self.xcodebuild_cmd + else: + raise Exception('Not supported with generator: ' + generator) + + for target in targets: + self.try_chdir(self.getBuildDir(target)) + err = os.system(cmd + ' clean') + self.restore_chdir() + + if err != 0: + raise Exception('Clean failed: ' + str(err)) + + def cleanGui(self, targets): + self.makeGui(targets, " clean") + + def open(self): + generator = self.getGeneratorFromConfig().cmakeName + if generator.startswith('Visual Studio'): + print 'Opening with %s...' % generator + self.open_internal(self.sln_filepath()) + + elif generator.startswith('Xcode'): + print 'Opening with %s...' % generator + self.open_internal(self.xcodeproj_filepath(), 'open') + + else: + raise Exception('Not supported with generator: ' + generator) + + def update(self): + print "Running Subversion update..." + err = os.system('svn update') + if err != 0: + raise Exception('Could not update from repository with error code code: ' + str(err)) + + def revision(self): + print self.find_revision() + + def find_revision(self): + return self.getGitRevision() + + def getGitRevision(self): + if sys.version_info < (2, 4): + raise Exception("Python 2.4 or greater required.") + + p = subprocess.Popen( + ["git", "log", "--pretty=format:%h", "-n", "1"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + stdout, stderr = p.communicate() + + if p.returncode != 0: + raise Exception('Could not get revision, git error: ' + str(p.returncode)) + + return stdout.strip() + + def getGitBranchName(self): + if sys.version_info < (2, 4): + raise Exception("Python 2.4 or greater required.") + + p = subprocess.Popen( + ["git", "rev-parse", "--abbrev-ref", "HEAD"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + stdout, stderr = p.communicate() + + if p.returncode != 0: + raise Exception('Could not get branch name, git error: ' + str(p.returncode)) + + return stdout.strip() + + def find_revision_svn(self): + if sys.version_info < (2, 4): + stdout = commands.getoutput('svn info') + else: + p = subprocess.Popen(['svn', 'info'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + + if p.returncode != 0: + raise Exception('Could not get revision - svn info failed with code: ' + str(p.returncode)) + + m = re.search('.*Revision: (\d+).*', stdout) + if not m: + raise Exception('Could not find revision number in svn info output.') + + return m.group(1) + + def kill(self): + if sys.platform == 'win32': + return os.system('taskkill /F /FI "IMAGENAME eq synergy*"') + else: + raise Exception('Not implemented for platform: ' + sys.platform) + + def doxygen(self): + self.enableMakeGui = False + + # The conf generates doc/doxygen.cfg from cmake/doxygen.cfg.in + self.configure(self.defaultTarget, '-DCONF_DOXYGEN:BOOL=TRUE') + + err = os.system('doxygen %s/%s' % (self.doc_dir, self.doxygen_filename)) + + if err != 0: + raise Exception('doxygen failed with error code: ' + str(err)) + + def dist(self, type, vcRedistDir, qtDir): + + # Package is supported by default. + package_unsupported = False + unixTarget = self.defaultTarget + + if type == '' or type == None: + self.dist_usage() + return + + moveExt = '' + + if type == 'src': + self.distSrc() + + elif type == 'rpm': + if sys.platform == 'linux2': + self.distRpm() + else: + package_unsupported = True + + elif type == 'deb': + if sys.platform == 'linux2': + self.distDeb() + else: + package_unsupported = True + + elif type == 'win': + if sys.platform == 'win32': + #self.distNsis(vcRedistDir, qtDir) + self.distWix() + else: + package_unsupported = True + + elif type == 'mac': + if sys.platform == 'darwin': + self.distMac() + else: + package_unsupported = True + + else: + raise Exception('Package type not supported: ' + type) + + if moveExt != '': + self.unixMove( + self.getGenerator().buildDir + '/release/*.' + moveExt, + self.getGenerator().binDir) + + if package_unsupported: + raise Exception( + ("Package type, '%s' is not supported for platform, '%s'") + % (type, sys.platform)) + + def distRpm(self): + rpmDir = self.getGenerator().buildDir + '/rpm' + if os.path.exists(rpmDir): + shutil.rmtree(rpmDir) + + os.makedirs(rpmDir) + + templateFile = open(self.cmake_dir + '/synergy.spec.in') + template = templateFile.read() + + template = template.replace('${in:version}', self.getVersionFromCmake()) + + specPath = rpmDir + '/synergy.spec' + + specFile = open(specPath, 'w') + specFile.write(template) + specFile.close() + + version = self.getVersionFromCmake() + target = '../../bin/synergy-%s-%s.rpm' % ( + version, self.getLinuxPlatform()) + + + try: + self.try_chdir(rpmDir) + cmd = 'rpmbuild -bb --define "_topdir `pwd`" synergy.spec' + print "Command: " + cmd + err = os.system(cmd) + if err != 0: + raise Exception('rpmbuild failed: ' + str(err)) + + self.unixMove('RPMS/*/*.rpm', target) + + cmd = 'rpmlint ' + target + print "Command: " + cmd + err = os.system(cmd) + if err != 0: + raise Exception('rpmlint failed: ' + str(err)) + + finally: + self.restore_chdir() + + def distDeb(self): + buildDir = self.getGenerator().buildDir + binDir = self.getGenerator().binDir + resDir = self.cmake_dir + + version = self.getVersionFromCmake() + package = '%s-%s-%s' % ( + self.project, version, self.getLinuxPlatform()) + + debDir = '%s/deb' % buildDir + if os.path.exists(debDir): + shutil.rmtree(debDir) + + metaDir = '%s/%s/DEBIAN' % (debDir, package) + os.makedirs(metaDir) + + templateFile = open(resDir + '/deb/control.in') + template = templateFile.read() + + template = template.replace('${in:version}', + self.getVersionFromCmake()) + + template = template.replace('${in:arch}', + self.getDebianArch()) + + controlPath = '%s/control' % metaDir + + controlFile = open(controlPath, 'w') + controlFile.write(template) + controlFile.close() + + targetBin = '%s/%s/usr/bin' % (debDir, package) + targetShare = '%s/%s/usr/share' % (debDir, package) + targetApplications = "%s/applications" % targetShare + targetIcons = "%s/icons" % targetShare + targetDocs = "%s/doc/%s" % (targetShare, self.project) + + os.makedirs(targetBin) + os.makedirs(targetApplications) + os.makedirs(targetIcons) + os.makedirs(targetDocs) + + for root, dirs, files in os.walk(debDir): + for d in dirs: + os.chmod(os.path.join(root, d), 0o0755) + + binFiles = ['synergy', 'synergyc', 'synergys', 'synergyd', 'syntool'] + for f in binFiles: + shutil.copy("%s/%s" % (binDir, f), targetBin) + target = "%s/%s" % (targetBin, f) + os.chmod(target, 0o0755) + err = os.system("strip " + target) + if err != 0: + raise Exception('strip failed: ' + str(err)) + + shutil.copy("%s/synergy.desktop" % resDir, targetApplications) + shutil.copy("%s/synergy.ico" % resDir, targetIcons) + + docTarget = "%s/doc/%s" % (targetShare, self.project) + + copyrightPath = "%s/deb/copyright" % resDir + shutil.copy(copyrightPath, docTarget) + + shutil.copy("%s/deb/changelog" % resDir, docTarget) + os.system("gzip -9 %s/changelog" % docTarget) + if err != 0: + raise Exception('gzip failed: ' + str(err)) + + for root, dirs, files in os.walk(targetShare): + for f in files: + os.chmod(os.path.join(root, f), 0o0644) + + target = '../../bin/%s.deb' % package + + try: + self.try_chdir(debDir) + + # TODO: consider dpkg-buildpackage (higher level tool) + cmd = 'fakeroot dpkg-deb --build %s' % package + print "Command: " + cmd + err = os.system(cmd) + if err != 0: + raise Exception('dpkg-deb failed: ' + str(err)) + + cmd = 'lintian %s.deb' % package + print "Command: " + cmd + err = os.system(cmd) + if err != 0: + raise Exception('lintian failed: ' + str(err)) + + self.unixMove('*.deb', target) + finally: + self.restore_chdir() + + def distSrc(self): + version = self.getVersionFromCmake() + name = (self.project + '-' + version + '-Source') + exportPath = self.getGenerator().buildDir + '/' + name + + if os.path.exists(exportPath): + print "Removing existing export..." + shutil.rmtree(exportPath) + + os.mkdir(exportPath) + + cmd = "git archive %s | tar -x -C %s" % ( + self.getGitBranchName(), exportPath) + + print 'Exporting repository to: ' + exportPath + err = os.system(cmd) + if err != 0: + raise Exception('Repository export failed: ' + str(err)) + + packagePath = '../' + self.getGenerator().binDir + '/' + name + '.tar.gz' + + try: + self.try_chdir(self.getGenerator().buildDir) + print 'Packaging to: ' + packagePath + err = os.system('tar cfvz ' + packagePath + ' ' + name) + if err != 0: + raise Exception('Package failed: ' + str(err)) + finally: + self.restore_chdir() + + def unixMove(self, source, dest): + print 'Moving ' + source + ' to ' + dest + err = os.system('mv ' + source + ' ' + dest) + if err != 0: + raise Exception('Package failed: ' + str(err)) + + def distMac(self): + self.loadConfig() + binDir = self.getGenerator().getBinDir('Release') + name = "Synergy" + dist = binDir + "/" + name + + # ensure dist dir is clean + if os.path.exists(dist): + shutil.rmtree(dist) + + os.makedirs(dist) + shutil.move(binDir + "/" + name + ".app", dist + "/" + name + ".app") + + self.try_chdir(dist) + err = os.system("ln -s /Applications") + self.restore_chdir() + + fileName = "%s-%s-%s.dmg" % ( + self.project, + self.getVersionFromCmake(), + self.getMacPackageName()) + + cmd = "hdiutil create " + fileName + " -srcfolder ./" + name + "/ -ov" + + self.try_chdir(binDir) + err = os.system(cmd) + self.restore_chdir() + + def distWix(self): + generator = self.getGeneratorFromConfig().cmakeName + + arch = 'x86' + if generator.endswith('Win64'): + arch = 'x64' + + version = self.getVersionFromCmake() + args = "/p:DefineConstants=\"Version=%s\"" % version + + self.run_vcbuild( + generator, 'release', 'synergy.sln', args, + 'src/setup/win32/', 'x86') + + filename = "%s-%s-Windows-%s.msi" % ( + self.project, + version, + arch) + + old = "bin/Release/synergy.msi" + new = "bin/Release/%s" % (filename) + + try: + os.remove(new) + except OSError: + pass + + os.rename(old, new) + + def distNsis(self, vcRedistDir, qtDir): + + if vcRedistDir == '': + raise Exception( + 'VC++ redist dir path not specified (--vcredist-dir).') + + if qtDir == '': + raise Exception( + 'QT SDK dir path not specified (--qt-dir).') + + generator = self.getGeneratorFromConfig().cmakeName + + arch = 'x86' + installDirVar = '$PROGRAMFILES32' + + if generator.endswith('Win64'): + arch = 'x64' + installDirVar = '$PROGRAMFILES64' + + templateFile = open(self.cmake_dir + '\Installer.nsi.in') + template = templateFile.read() + + template = template.replace('${in:version}', self.getVersionFromCmake()) + template = template.replace('${in:arch}', arch) + template = template.replace('${in:vcRedistDir}', vcRedistDir) + template = template.replace('${in:qtDir}', qtDir) + template = template.replace('${in:installDirVar}', installDirVar) + + nsiPath = self.getGenerator().buildDir + '\Installer.nsi' + nsiFile = open(nsiPath, 'w') + nsiFile.write(template) + nsiFile.close() + + command = 'makensis ' + nsiPath + print 'NSIS command: ' + command + err = os.system(command) + if err != 0: + raise Exception('Package failed: ' + str(err)) + + def getVersionFromCmake(self): + cmakeFile = open('CMakeLists.txt') + cmake = cmakeFile.read() + + majorRe = re.search('VERSION_MAJOR (\d+)', cmake) + major = majorRe.group(1) + + minorRe = re.search('VERSION_MINOR (\d+)', cmake) + minor = minorRe.group(1) + + revRe = re.search('VERSION_REV (\d+)', cmake) + rev = revRe.group(1) + + return major + '.' + minor + '.' + rev + + def ftpUpload(self, ftp, source, target): + print "Uploading '%s' as '%s' to FTP server '%s'..." % ( + source, target, ftp.host) + ftp.run(source, target) + print 'Done' + + def distftp(self, type, ftp): + if not type: + raise Exception('Platform type not specified.') + + self.loadConfig() + + binDir = self.getGenerator().getBinDir('Release') + + packageSource = binDir + '/' + self.dist_name(type) + packageTarget = self.dist_name_rev(type) + self.ftpUpload(ftp, packageSource, packageTarget) + + if (type != 'src'): + pluginsDir = binDir + '/plugins' + nsPluginSource = self.findLibraryFile(type, pluginsDir, 'ns') + nsPluginTarget = self.getLibraryDistFilename(type, pluginsDir, 'ns') + self.ftpUpload(ftp, nsPluginSource, nsPluginTarget) + + def getLibraryDistFilename(self, type, dir, name): + (platform, packageExt, libraryExt) = self.getDistributePlatformInfo(type) + branch = self.getGitBranchName() + revision = self.getGitRevision() + firstPart = '%s-%s-%s-%s' % (name, branch, revision, platform) + + filename = '%s.%s' % (firstPart, libraryExt) + if type == 'rpm' or type == 'deb': + # linux is a bit special, include dist type (deb/rpm in filename) + filename = '%s-%s.%s' % (firstPart, packageExt, libraryExt) + + return filename + + def findLibraryFile(self, type, dir, name): + (platform, packageExt, libraryExt) = self.getDistributePlatformInfo(type) + ext = libraryExt + + pattern = name + '\.' + ext + + for filename in os.listdir(dir): + if re.search(pattern, filename): + return dir + '/' + filename + + raise Exception('Could not find library name with pattern: ' + pattern) + + def getDistributePlatformInfo(self, type): + ext = None + libraryExt = None + platform = None + + if type == 'src': + ext = 'tar.gz' + platform = 'Source' + + elif type == 'rpm' or type == 'deb': + ext = type + libraryExt = 'so' + platform = self.getLinuxPlatform() + + elif type == 'win': + # get platform based on last generator used + ext = 'msi' + libraryExt = 'dll' + generator = self.getGeneratorFromConfig().cmakeName + if generator.find('Win64') != -1: + platform = 'Windows-x64' + else: + platform = 'Windows-x86' + + elif type == 'mac': + ext = "dmg" + libraryExt = 'dylib' + platform = self.getMacPackageName() + + if not platform: + raise Exception('Unable to detect distributable platform.') + + return (platform, ext, libraryExt) + + def dist_name(self, type): + (platform, packageExt, libraryExt) = self.getDistributePlatformInfo(type) + ext = packageExt + + pattern = ( + re.escape(self.project + '-') + '\d+\.\d+\.\d+' + + re.escape('-' + platform + '.' + ext)) + + for filename in os.listdir(self.getBinDir('Release')): + if re.search(pattern, filename): + return filename + + # still here? package probably not created yet. + raise Exception('Could not find package name with pattern: ' + pattern) + + def dist_name_rev(self, type): + # find the version number (we're puting the rev in after this) + pattern = '(\d+\.\d+\.\d+)' + replace = "%s-%s" % ( + self.getGitBranchName(), self.getGitRevision()) + return re.sub(pattern, replace, self.dist_name(type)) + + def getDebianArch(self): + if os.uname()[4][:3] == 'arm': + return 'armhf' + + # os_bits should be loaded with '32bit' or '64bit' + import platform + (os_bits, other) = platform.architecture() + + # get platform based on current platform + if os_bits == '32bit': + return 'i386' + elif os_bits == '64bit': + return 'amd64' + else: + raise Exception("unknown os bits: " + os_bits) + + def getLinuxPlatform(self): + if os.uname()[4][:3] == 'arm': + return 'Linux-armv6l' + + # os_bits should be loaded with '32bit' or '64bit' + import platform + (os_bits, other) = platform.architecture() + + # get platform based on current platform + if os_bits == '32bit': + return 'Linux-i686' + elif os_bits == '64bit': + return 'Linux-x86_64' + else: + raise Exception("unknown os bits: " + os_bits) + + def dist_usage(self): + print ('Usage: %s package [package-type]\n' + '\n' + 'Replace [package-type] with one of:\n' + ' src .tar.gz source (Posix only)\n' + ' rpm .rpm package (Red Hat)\n' + ' deb .deb paclage (Debian)\n' + ' win .exe installer (Windows)\n' + ' mac .dmg package (Mac OS X)\n' + '\n' + 'Example: %s package src-tgz') % (self.this_cmd, self.this_cmd) + + def about(self): + print ('Help Me script, from the Synergy project.\n' + '%s\n' + '\n' + 'For help, run: %s help') % (self.website_url, self.this_cmd) + + def try_chdir(self, dir): + global prevdir + + if dir == '': + prevdir = '' + return + + # Ensure temp build dir exists. + if not os.path.exists(dir): + print 'Creating dir: ' + dir + os.makedirs(dir) + + prevdir = os.path.abspath(os.curdir) + + # It will exist by this point, so it's safe to chdir. + print 'Entering dir: ' + dir + os.chdir(dir) + + def restore_chdir(self): + global prevdir + if prevdir == '': + return + print 'Going back to: ' + prevdir + os.chdir(prevdir) + + def open_internal(self, project_filename, application = ''): + + if not os.path.exists(project_filename): + raise Exception('Project file (%s) not found, run hm conf first.' % project_filename) + else: + path = project_filename + + if application != '': + path = application + ' ' + path + + err = os.system(path) + if err != 0: + raise Exception('Could not open project with error code code: ' + str(err)) + + def setup(self, target=''): + print "Running setup..." + + oldGenerator = self.findGeneratorFromConfig() + if not oldGenerator == None: + for target in ['debug', 'release']: + buildDir = oldGenerator.getBuildDir(target) + + cmakeCacheFilename = 'CMakeCache.txt' + if buildDir != '': + cmakeCacheFilename = buildDir + '/' + cmakeCacheFilename + + if os.path.exists(cmakeCacheFilename): + print "Removing %s, since generator changed." % cmakeCacheFilename + os.remove(cmakeCacheFilename) + + # always either get generator from args, or prompt user when + # running setup + generator = self.get_generator_from_prompt() + + config = self.getConfig() + config.set('hm', 'setup_version', self.setup_version) + + # store the generator so we don't need to ask again + config.set('cmake', 'generator', generator) + + self.write_config(config) + + # for all targets, set conf not run + self.setConfRun('all', False) + self.setConfRun('debug', False) + self.setConfRun('release', False) + + print "Setup complete." + + def getConfig(self): + if os.path.exists(self.configFilename): + config = ConfigParser.ConfigParser() + config.read(self.configFilename) + else: + config = ConfigParser.ConfigParser() + + if not config.has_section('hm'): + config.add_section('hm') + + if not config.has_section('cmake'): + config.add_section('cmake') + + return config + + def write_config(self, config, target=''): + if not os.path.isdir(self.configDir): + os.mkdir(self.configDir) + configfile = open(self.configFilename, 'wb') + config.write(configfile) + + def getGeneratorFromConfig(self): + generator = self.findGeneratorFromConfig() + if generator: + return generator + + raise Exception("Could not find generator: " + name) + + def findGeneratorFromConfig(self): + config = ConfigParser.RawConfigParser() + config.read(self.configFilename) + + if not config.has_section('cmake'): + return None + + name = config.get('cmake', 'generator') + + generators = self.get_generators() + keys = generators.keys() + keys.sort() + for k in keys: + if generators[k].cmakeName == name: + return generators[k] + + return None + + def min_setup_version(self, version): + if os.path.exists(self.configFilename): + config = ConfigParser.RawConfigParser() + config.read(self.configFilename) + + try: + return config.getint('hm', 'setup_version') >= version + except: + return False + else: + return False + + def hasConfRun(self, target): + if self.min_setup_version(2): + config = ConfigParser.RawConfigParser() + config.read(self.configFilename) + try: + return config.getboolean('hm', 'conf_done_' + target) + except: + return False + else: + return False + + def setConfRun(self, target, hasRun=True): + if self.min_setup_version(3): + config = ConfigParser.RawConfigParser() + config.read(self.configFilename) + config.set('hm', 'conf_done_' + target, hasRun) + self.write_config(config) + else: + raise Exception("User does not have correct setup version.") + + def get_generators(self): + if sys.platform == 'win32': + return self.win32_generators + elif sys.platform in ['linux2', 'sunos5', 'freebsd7', 'aix5']: + return self.unix_generators + elif sys.platform == 'darwin': + return self.darwin_generators + else: + raise Exception('Unsupported platform: ' + sys.platform) + + def get_generator_from_prompt(self): + return self.getGenerator().cmakeName + + def getGenerator(self): + generators = self.get_generators() + if len(generators.keys()) == 1: + return generators[generators.keys()[0]] + + # if user has specified a generator as an argument + if self.generator_id: + return generators[int(self.generator_id)] + + conf = self.findGeneratorFromConfig() + if conf: + return conf + + raise Exception( + 'Generator not specified, use -g arg ' + + '(use `hm genlist` for a list of generators).') + + def setup_generator_prompt(self, generators): + + if self.no_prompts: + raise Exception('User prompting is disabled.') + + prompt = 'Enter a number:' + print prompt, + + generator_id = raw_input() + + if generator_id in generators: + print 'Selected generator:', generators[generator_id] + else: + print 'Invalid number, try again.' + self.setup_generator_prompt(generators) + + return generators[generator_id] + + def get_vcvarsall(self, generator): + import platform, _winreg + + # os_bits should be loaded with '32bit' or '64bit' + (os_bits, other) = platform.architecture() + + # visual studio is a 32-bit app, so when we're on 64-bit, we need to check the WoW dungeon + if os_bits == '64bit': + key_name = r'SOFTWARE\Wow6432Node\Microsoft\VisualStudio\SxS\VS7' + else: + key_name = r'SOFTWARE\Microsoft\VisualStudio\SxS\VC7' + + try: + key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, key_name) + except: + raise Exception('Unable to open Visual Studio registry key. Application may not be installed.') + + if generator.startswith('Visual Studio 8'): + value,type = _winreg.QueryValueEx(key, '8.0') + elif generator.startswith('Visual Studio 9'): + value,type = _winreg.QueryValueEx(key, '9.0') + elif generator.startswith('Visual Studio 10'): + value,type = _winreg.QueryValueEx(key, '10.0') + else: + raise Exception('Cannot determine vcvarsall.bat location for: ' + generator) + + # not sure why, but the value on 64-bit differs slightly to the original + if os_bits == '64bit': + path = value + r'vc\vcvarsall.bat' + else: + path = value + r'vcvarsall.bat' + + if not os.path.exists(path): + raise Exception("'%s' not found." % path) + + return path + + def run_vcbuild(self, generator, mode, solution, args='', dir='', config32='Win32'): + import platform + + # os_bits should be loaded with '32bit' or '64bit' + (os_bits, other) = platform.architecture() + # Now we choose the parameters bases on OS 32/64 and our target 32/64 + # http://msdn.microsoft.com/en-us/library/x4d2c09s%28VS.80%29.aspx + + # valid options are only: ia64 amd64 x86_amd64 x86_ia64 + # but calling vcvarsall.bat does not garantee that it will work + # ret code from vcvarsall.bat is always 0 so the only way of knowing that I worked is by analysing the text output + # ms bugg: install VS9, FeaturePack, VS9SP1 and you'll obtain a vcvarsall.bat that fails. + if generator.find('Win64') != -1: + # target = 64bit + if os_bits == '32bit': + vcvars_platform = 'x86_amd64' # 32bit OS building 64bit app + else: + vcvars_platform = 'amd64' # 64bit OS building 64bit app + config_platform = 'x64' + else: # target = 32bit + vcvars_platform = 'x86' # 32/64bit OS building 32bit app + config_platform = config32 + + if mode == 'release': + config = 'Release' + else: + config = 'Debug' + + if generator.startswith('Visual Studio 10'): + cmd = ('@echo off\n' + 'call "%s" %s \n' + 'cd "%s"\n' + 'msbuild /nologo %s /p:Configuration="%s" /p:Platform="%s" "%s"' + ) % (self.get_vcvarsall(generator), vcvars_platform, dir, args, config, config_platform, solution) + else: + config = config + '|' + config_platform + cmd = ('@echo off\n' + 'call "%s" %s \n' + 'cd "%s"\n' + 'vcbuild /nologo %s "%s" "%s"' + ) % (self.get_vcvarsall(generator), vcvars_platform, dir, args, solution, config) + + # Generate a batch file, since we can't use environment variables directly. + temp_bat = self.getBuildDir() + r'\vcbuild.bat' + file = open(temp_bat, 'w') + file.write(cmd) + file.close() + + err = os.system(temp_bat) + if err != 0: + raise Exception('Microsoft compiler failed with error code: ' + str(err)) + + def ensure_setup_latest(self): + if not self.min_setup_version(self.setup_version): + self.setup() + + def reformat(self): + err = os.system( + r'tool\astyle\AStyle.exe ' + '--quiet --suffix=none --style=java --indent=force-tab=4 --recursive ' + 'lib/*.cpp lib/*.h cmd/*.cpp cmd/*.h') + + if err != 0: + raise Exception('Reformat failed with error code: ' + str(err)) + + def printGeneratorList(self): + generators = self.get_generators() + keys = generators.keys() + keys.sort() + for k in keys: + print str(k) + ': ' + generators[k].cmakeName + + def getMacVersion(self): + if not self.macSdk: + raise Exception("Mac OS X SDK not set.") + + result = re.search('(\d+)\.(\d+)', self.macSdk) + if not result: + print versions + raise Exception("Could not find Mac OS X version.") + + major = int(result.group(1)) + minor = int(result.group(2)) + return (major, minor) + + def getMacPackageName(self): + + (major, minor) = self.getMacVersion() + + if major == 10: + if minor <= 4: + # 10.4: intel and power pc + arch = "Universal" + elif minor <= 6: + # 10.5: 32-bit intel + arch = "i386" + else: + # 10.7: 64-bit intel (gui only) + arch = "x86_64" + else: + raise Exception("Mac OS major version unknown: " + + str(major)) + + # version is major and minor with no dots (e.g. 106) + version = str(major) + str(minor) + + return "MacOSX%s-%s" % (version, arch) + + def reset(self): + if os.path.exists('build'): + shutil.rmtree('build') + + if os.path.exists('bin'): + shutil.rmtree('bin') + + if os.path.exists('lib'): + shutil.rmtree('lib') + + if os.path.exists('src/gui/tmp'): + shutil.rmtree('src/gui/tmp') + + # qt 4.3 generates ui_ files. + for filename in glob.glob("src/gui/ui_*"): + os.remove(filename) + +# the command handler should be called only from hm.py (i.e. directly +# from the command prompt). the purpose of this class is so that we +# don't need to do argument handling all over the place in the internal +# commands class. +class CommandHandler: + ic = InternalCommands() + build_targets = [] + vcRedistDir = '' + qtDir = '' + + def __init__(self, argv, opts, args, verbose): + + self.ic.verbose = verbose + + self.opts = opts + self.args = args + + for o, a in self.opts: + if o == '--no-prompts': + self.ic.no_prompts = True + elif o in ('-g', '--generator'): + self.ic.generator_id = a + elif o == '--skip-gui': + self.ic.enableMakeGui = False + elif o == '--skip-core': + self.ic.enableMakeCore = False + elif o in ('-d', '--debug'): + self.build_targets += ['debug',] + elif o in ('-r', '--release'): + self.build_targets += ['release',] + elif o == '--vcredist-dir': + self.vcRedistDir = a + elif o == '--qt-dir': + self.qtDir = a + elif o == '--mac-sdk': + self.ic.macSdk = a + elif o == '--mac-identity': + self.ic.macIdentity = a + + def about(self): + self.ic.about() + + def setup(self): + self.ic.setup() + + def configure(self): + self.ic.configureAll(self.build_targets) + + def build(self): + self.ic.build(self.build_targets) + + def clean(self): + self.ic.clean(self.build_targets) + + def update(self): + self.ic.update() + + def install(self): + print 'Not yet implemented: install' + + def doxygen(self): + self.ic.doxygen() + + def dist(self): + + type = None + if len(self.args) > 0: + type = self.args[0] + + self.ic.dist(type, self.vcRedistDir, self.qtDir) + + def distftp(self): + type = None + host = None + user = None + password = None + dir = None + + if len(self.args) > 0: + type = self.args[0] + + for o, a in self.opts: + if o == '--host': + host = a + elif o == '--user': + user = a + elif o == '--pass': + password = a + elif o == '--dir': + dir = a + + if not host: + raise Exception('FTP host was not specified.') + + ftp = ftputil.FtpUploader( + host, user, password, dir) + + self.ic.distftp(type, ftp) + + def destroy(self): + self.ic.destroy() + + def kill(self): + self.ic.kill() + + def usage(self): + self.ic.usage() + + def revision(self): + self.ic.revision() + + def reformat(self): + self.ic.reformat() + + def open(self): + self.ic.open() + + def genlist(self): + self.ic.printGeneratorList() + + def reset(self): + self.ic.reset() + + def signwin(self): + pfx = None + pwd = None + dist = False + for o, a in self.opts: + if o == '--pfx': + pfx = a + elif o == '--pwd': + pwd = a + elif o == '--dist': + dist = True + self.ic.signwin(pfx, pwd, dist) + + def signmac(self): + self.ic.signmac() diff --git a/ext/toolchain/shitindent.py b/ext/toolchain/shitindent.py new file mode 100644 index 00000000..a6df18d1 --- /dev/null +++ b/ext/toolchain/shitindent.py @@ -0,0 +1,31 @@ + def getDebianArch(self): + if os.uname()[4][:3] == 'arm': + return 'armhf' + + # os_bits should be loaded with '32bit' or '64bit' + import platform + (os_bits, other) = platform.architecture() + + # get platform based on current platform + if os_bits == '32bit': + return 'i386' + elif os_bits == '64bit': + return 'amd64' + else: + raise Exception("unknown os bits: " + os_bits) + + def getLinuxPlatform(self): + if os.uname()[4][:3] == 'arm': + return 'Linux-armv6l' + + # os_bits should be loaded with '32bit' or '64bit' + import platform + (os_bits, other) = platform.architecture() + + # get platform based on current platform + if os_bits == '32bit': + return 'Linux-i686' + elif os_bits == '64bit': + return 'Linux-x86_64' + else: + raise Exception("unknown os bits: " + os_bits) \ No newline at end of file