Fixed issue 547
This commit is contained in:
parent
b2d08a0beb
commit
1a4af219a9
|
@ -1,7 +1,6 @@
|
|||
# TODO: split this file up, it's too long!
|
||||
|
||||
import sys, os, ConfigParser, subprocess, shutil
|
||||
from getopt import getopt
|
||||
|
||||
class InternalCommands:
|
||||
|
||||
|
@ -25,6 +24,12 @@ class InternalCommands:
|
|||
|
||||
# try_chdir(...) and restore_chdir() will use this
|
||||
prevdir = ''
|
||||
|
||||
# by default, no index specified as arg
|
||||
generator_index = None
|
||||
|
||||
# by default, prompt user for input
|
||||
no_prompts = False
|
||||
|
||||
win32_generators = {
|
||||
'1' : 'Visual Studio 10',
|
||||
|
@ -33,9 +38,6 @@ class InternalCommands:
|
|||
'4' : 'Visual Studio 9 2008 Win64',
|
||||
'5' : 'Visual Studio 8 2005',
|
||||
'6' : 'Visual Studio 8 2005 Win64',
|
||||
'7' : 'Visual Studio 7',
|
||||
'8' : 'Visual Studio 7 .NET 2003',
|
||||
'9' : 'Visual Studio 6',
|
||||
'10' : 'CodeBlocks - MinGW Makefiles',
|
||||
'11' : 'CodeBlocks - Unix Makefiles',
|
||||
'12': 'Eclipse CDT4 - MinGW Makefiles',
|
||||
|
@ -77,7 +79,7 @@ class InternalCommands:
|
|||
|
||||
def usage(self):
|
||||
app = sys.argv[0]
|
||||
print ('Usage: %s [command]\n'
|
||||
print ('Usage: %s <command> [-g <index>|-v|--no-prompts|<command-options>]\n'
|
||||
'\n'
|
||||
'Replace [command] with one of:\n'
|
||||
' about Show information about this script\n'
|
||||
|
@ -86,21 +88,19 @@ class InternalCommands:
|
|||
' 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'
|
||||
' destroy Destroy all temporary files (bin and build)\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'
|
||||
' hammer Golden hammer (config, build, package)\n'
|
||||
' reformat Reformat .cpp and .h files using AStyle\n'
|
||||
' usage Shows the help screen\n'
|
||||
'\n'
|
||||
'Example: %s conf'
|
||||
'Example: %s build -g 3'
|
||||
) % (app, app)
|
||||
|
||||
def configure(self, generator):
|
||||
err = self.configure_internal(generator)
|
||||
|
||||
def configure(self):
|
||||
err = self.configure_internal()
|
||||
|
||||
if err == 0:
|
||||
print ('Configure complete!\n\n'
|
||||
|
@ -132,28 +132,46 @@ class InternalCommands:
|
|||
break
|
||||
|
||||
if not found_cmd:
|
||||
msg = 'CMake 2.8.0 not installed. Auto download now? [Y/n]'
|
||||
print msg,
|
||||
|
||||
yn = raw_input()
|
||||
if yn in ['n', 'N']:
|
||||
|
||||
found_cmake = False
|
||||
|
||||
# if prompting allowed
|
||||
if not self.no_prompts:
|
||||
msg = 'CMake 2.8.0 not installed. Auto download now? [Y/n]'
|
||||
print msg,
|
||||
yn = raw_input()
|
||||
|
||||
# if response was anyting but no
|
||||
if yn not in ['n', 'N']:
|
||||
if not os.path.exists('tool'):
|
||||
os.mkdir('tool')
|
||||
|
||||
os.system(r'svn checkout https://synergy-plus.googlecode.com/svn/tools/win/cmake tool\cmake')
|
||||
found_cmd = r'..\tool\cmake\bin\%s' % self.cmake_cmd
|
||||
found_cmake = True
|
||||
|
||||
# if cmake was not found
|
||||
if not found_cmake:
|
||||
print 'Cannot continue without CMake, exiting.'
|
||||
sys.exit(1)
|
||||
else:
|
||||
if not os.path.exists('tool'):
|
||||
os.mkdir('tool')
|
||||
os.system(r'svn checkout https://synergy-plus.googlecode.com/svn/tools/win/cmake tool\cmake')
|
||||
found_cmd = r'..\tool\cmake\bin\%s' % self.cmake_cmd
|
||||
|
||||
return found_cmd
|
||||
else:
|
||||
return self.cmake_cmd
|
||||
|
||||
def configure_internal(self, generator = None):
|
||||
|
||||
self.ensure_setup_latest(generator)
|
||||
def configure_internal(self):
|
||||
|
||||
# ensure latest setup and do not ask config for generator (only fall
|
||||
# back to prompt if not specified as arg)
|
||||
self.ensure_setup_latest()
|
||||
|
||||
# ensure that we have access to cmake
|
||||
_cmake_cmd = self.persist_cmake()
|
||||
generator = self.get_generator()
|
||||
|
||||
# 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.get_generator_from_config()
|
||||
|
||||
if generator != '':
|
||||
cmake_args = '%s -G "%s"' % (self.source_dir, generator)
|
||||
|
@ -184,7 +202,7 @@ class InternalCommands:
|
|||
if self.configure_internal() != 0:
|
||||
return False
|
||||
|
||||
generator = self.get_generator()
|
||||
generator = self.get_generator_from_config()
|
||||
|
||||
if generator == "Unix Makefiles":
|
||||
|
||||
|
@ -199,7 +217,7 @@ class InternalCommands:
|
|||
print 'GNU Make failed:', err
|
||||
return False
|
||||
|
||||
elif generator.startswith('Visual Studio 10') or generator.startswith('Visual Studio 8') or generator.startswith('Visual Studio 9'):
|
||||
elif generator.startswith('Visual Studio'):
|
||||
|
||||
ret = self.run_vcbuild(generator, mode)
|
||||
|
||||
|
@ -228,7 +246,7 @@ class InternalCommands:
|
|||
|
||||
def clean(self, mode = None):
|
||||
|
||||
generator = self.get_generator()
|
||||
generator = self.get_generator_from_config()
|
||||
|
||||
if generator == "Unix Makefiles":
|
||||
|
||||
|
@ -243,6 +261,7 @@ class InternalCommands:
|
|||
print 'GNU Make failed: %s' % err
|
||||
return False
|
||||
|
||||
# special case for version 10, use new /target:clean
|
||||
elif generator.startswith('Visual Studio 10'):
|
||||
|
||||
ret = self.run_vcbuild(generator, mode, '/target:clean')
|
||||
|
@ -253,7 +272,8 @@ class InternalCommands:
|
|||
print 'VCBuild failed:', ret
|
||||
return False
|
||||
|
||||
elif generator.startswith('Visual Studio 8') or generator.startswith('Visual Studio 9'):
|
||||
# any other version of visual studio, use /clean
|
||||
elif generator.startswith('Visual Studio'):
|
||||
|
||||
ret = self.run_vcbuild(generator, mode, '/clean')
|
||||
|
||||
|
@ -281,7 +301,7 @@ class InternalCommands:
|
|||
return False
|
||||
|
||||
def open(self):
|
||||
generator = self.get_generator()
|
||||
generator = self.get_generator_from_config()
|
||||
if generator.startswith('Visual Studio'):
|
||||
print 'Opening with %s...' % generator
|
||||
self.open_internal(self.sln_filepath())
|
||||
|
@ -302,17 +322,6 @@ class InternalCommands:
|
|||
# While this doesn't print out the revision specifically, it will do.
|
||||
os.system('svn info')
|
||||
|
||||
def destroy(argv):
|
||||
msg = "Are you sure you want to remove the ./bin/ directory? [y/N]"
|
||||
print msg,
|
||||
|
||||
yn = raw_input()
|
||||
if yn in ['y', 'Y']:
|
||||
try:
|
||||
shutil.rmtree(self.bin_dir)
|
||||
except:
|
||||
print "Warning: Could not remove ./bin/ directory."
|
||||
|
||||
def kill(self):
|
||||
if sys.platform == 'win32':
|
||||
os.system('taskkill /F /FI "IMAGENAME eq synergy*"')
|
||||
|
@ -431,19 +440,12 @@ class InternalCommands:
|
|||
os.system(path)
|
||||
return True
|
||||
|
||||
def setup(self, generator = None):
|
||||
def setup(self):
|
||||
print "Running setup..."
|
||||
|
||||
# If no generator specified, prompt the user.
|
||||
if generator == None:
|
||||
if sys.platform == 'win32':
|
||||
generator = self.get_setup_generator(self.win32_generators)
|
||||
elif sys.platform in ['linux2', 'sunos5', 'freebsd7']:
|
||||
generator = self.get_setup_generator(self.unix_generators)
|
||||
elif sys.platform == 'darwin':
|
||||
generator = self.get_setup_generator(self.darwin_generators)
|
||||
else:
|
||||
raise Exception('Unsupported platform: ' + sys.platform)
|
||||
# always either get generator from args, or prompt user when
|
||||
# running setup
|
||||
generator = self.get_generator_from_prompt()
|
||||
|
||||
# Create build dir, since config file resides there.
|
||||
if not os.path.exists(self.bin_dir):
|
||||
|
@ -462,6 +464,8 @@ class InternalCommands:
|
|||
config.add_section('cmake')
|
||||
|
||||
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)
|
||||
|
@ -477,10 +481,14 @@ class InternalCommands:
|
|||
configfile = open(self.config_filepath(), 'wb')
|
||||
config.write(configfile)
|
||||
|
||||
def get_generator(self):
|
||||
config = ConfigParser.RawConfigParser()
|
||||
config.read(self.config_filepath())
|
||||
return config.get('cmake', 'generator')
|
||||
def get_generator_from_config(self):
|
||||
if self.generator_index:
|
||||
generators = self.get_generators()
|
||||
return generators[self.generator_index]
|
||||
else:
|
||||
config = ConfigParser.RawConfigParser()
|
||||
config.read(self.config_filepath())
|
||||
return config.get('cmake', 'generator')
|
||||
|
||||
def min_setup_version(self, version):
|
||||
if os.path.exists(self.config_filepath()):
|
||||
|
@ -514,24 +522,48 @@ class InternalCommands:
|
|||
else:
|
||||
raise Exception("User does not have correct setup version.")
|
||||
|
||||
def get_setup_generator(self, generators):
|
||||
|
||||
generator_options = ''
|
||||
generators_sorted = sorted(generators.iteritems(), key=lambda t: int(t[0]))
|
||||
def get_generators(self):
|
||||
if sys.platform == 'win32':
|
||||
return self.win32_generators
|
||||
elif sys.platform in ['linux2', 'sunos5', 'freebsd7']:
|
||||
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):
|
||||
|
||||
for id, generator in generators_sorted:
|
||||
generator_options += '\n ' + id + ': ' + generator
|
||||
generators = self.get_generators()
|
||||
|
||||
# if user has specified a generator as an argument
|
||||
if self.generator_index:
|
||||
return generators[self.generator_index]
|
||||
|
||||
# if we can accept user input
|
||||
elif not self.no_prompts:
|
||||
generator_options = ''
|
||||
generators_sorted = sorted(generators.iteritems(), key=lambda t: int(t[0]))
|
||||
|
||||
for id, generator in generators_sorted:
|
||||
generator_options += '\n ' + id + ': ' + generator
|
||||
|
||||
print ('\nChoose a CMake generator:%s'
|
||||
) % generator_options
|
||||
print ('\nChoose a CMake generator:%s'
|
||||
) % generator_options
|
||||
|
||||
return self.setup_generator_prompt(generators)
|
||||
return self.setup_generator_prompt(generators)
|
||||
|
||||
else:
|
||||
raise Exception('No generator specified, and cannot prompt user.')
|
||||
|
||||
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:
|
||||
|
@ -612,7 +644,7 @@ class InternalCommands:
|
|||
'call "%s" %s \n'
|
||||
'vcbuild /nologo %s "%s" "%s"'
|
||||
) % (self.get_vcvarsall(generator), vcvars_platform, args, self.sln_filepath(), config)
|
||||
print cmd
|
||||
|
||||
# Generate a batch file, since we can't use environment variables directly.
|
||||
temp_bat = self.bin_dir + r'\vcbuild.bat'
|
||||
file = open(temp_bat, 'w')
|
||||
|
@ -621,51 +653,9 @@ class InternalCommands:
|
|||
|
||||
return os.system(temp_bat)
|
||||
|
||||
def ensure_setup_latest(self, generator = None):
|
||||
def ensure_setup_latest(self):
|
||||
if not self.min_setup_version(self.setup_version):
|
||||
self.setup(generator)
|
||||
|
||||
class HammerBuild:
|
||||
generator = None
|
||||
target_dir = None
|
||||
|
||||
def __init__(self, _generator, _target_dir, ic):
|
||||
self.generator = _generator
|
||||
self.target_dir = _target_dir
|
||||
|
||||
def run(self):
|
||||
ic.bin_dir = self.target_dir
|
||||
configure(self.generator)
|
||||
build(['debug'])
|
||||
build(['release'])
|
||||
|
||||
def hammer(self):
|
||||
|
||||
hammer_builds = []
|
||||
if sys.platform == 'win32':
|
||||
hammer_builds += [
|
||||
HammerBuild('Visual Studio 9 2008', 'bin32', self),
|
||||
HammerBuild('Visual Studio 9 2008 Win64', 'bin64', self)]
|
||||
elif sys.platform in ['linux2', 'sunos5', 'freebsd7']:
|
||||
hammer_builds += [
|
||||
HammerBuild('Unix Makefiles', 'bin', self)]
|
||||
elif sys.platform == 'darwin':
|
||||
hammer_builds += [
|
||||
HammerBuild('Xcode', 'bin', self)]
|
||||
|
||||
for hb in hammer_builds:
|
||||
hb.run()
|
||||
|
||||
package_types = []
|
||||
if sys.platform == 'win32':
|
||||
package_types += ['win']
|
||||
elif sys.platform == 'linux2':
|
||||
package_types += ['src', 'rpm', 'deb']
|
||||
elif sys.platform == 'darwin':
|
||||
package_types += ['mac']
|
||||
|
||||
for pt in package_types:
|
||||
package(pt)
|
||||
self.setup()
|
||||
|
||||
def reformat(self):
|
||||
# TODO: error handling
|
||||
|
@ -681,19 +671,24 @@ class InternalCommands:
|
|||
class CommandHandler:
|
||||
ic = InternalCommands()
|
||||
|
||||
def __init__(self, argv, optarg_data):
|
||||
self.opts, self.args = getopt(argv, optarg_data[0], optarg_data[1])
|
||||
def __init__(self, argv, opts, args):
|
||||
|
||||
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_index = a
|
||||
|
||||
def get_build_mode(self):
|
||||
mode = None
|
||||
if len(self.args) > 0:
|
||||
mode = self.args[0]
|
||||
else:
|
||||
for o, a in self.opts:
|
||||
if o == '-d':
|
||||
mode = 'debug'
|
||||
elif o == '-r':
|
||||
mode = 'release'
|
||||
for o, a in self.opts:
|
||||
if o == ('-d', '--debug'):
|
||||
mode = 'debug'
|
||||
elif o == ('-r', '--release'):
|
||||
mode = 'release'
|
||||
return mode
|
||||
|
||||
def about(self):
|
||||
|
@ -703,10 +698,7 @@ class CommandHandler:
|
|||
self.ic.setup()
|
||||
|
||||
def configure(self):
|
||||
generator = None
|
||||
if len(self.args) > 0:
|
||||
generator = self.args[0]
|
||||
self.ic.configure(generator)
|
||||
self.ic.configure()
|
||||
|
||||
def build(self):
|
||||
self.ic.build(self.get_build_mode())
|
||||
|
|
74
hm.py
74
hm.py
|
@ -16,25 +16,32 @@
|
|||
|
||||
import sys, os
|
||||
from build import commands
|
||||
from getopt import getopt
|
||||
|
||||
# options used by all commands
|
||||
global_options = 'g:v'
|
||||
global_options_long = ['no-prompts', 'generator=', 'verbose']
|
||||
|
||||
# options used by build related commands
|
||||
build_options = 'dr'
|
||||
build_options_long = ['debug', 'release']
|
||||
|
||||
# list of valid commands as keys. the values are optarg strings, but most
|
||||
# are None for now (this is mainly for extensibility)
|
||||
cmd_dict = {
|
||||
'about' : [None, []],
|
||||
'setup' : [None, []],
|
||||
'configure' : [None, []],
|
||||
'build' : ['dr', []],
|
||||
'clean' : ['dr', []],
|
||||
'update' : [None, []],
|
||||
'install' : [None, []],
|
||||
'package' : [None, []],
|
||||
'destroy' : [None, []],
|
||||
'kill' : [None, []],
|
||||
'usage' : [None, []],
|
||||
'revision' : [None, []],
|
||||
'hammer' : [None, []],
|
||||
'reformat' : [None, []],
|
||||
'open' : [None, []],
|
||||
cmd_opt_dict = {
|
||||
'about' : ['', []],
|
||||
'setup' : ['', []],
|
||||
'configure' : ['', []],
|
||||
'build' : [build_options, build_options_long],
|
||||
'clean' : [build_options, build_options_long],
|
||||
'update' : ['', []],
|
||||
'install' : ['', []],
|
||||
'package' : ['', []],
|
||||
'kill' : ['', []],
|
||||
'usage' : ['', []],
|
||||
'revision' : ['', []],
|
||||
'reformat' : ['', []],
|
||||
'open' : ['', []],
|
||||
}
|
||||
|
||||
# aliases to valid commands
|
||||
|
@ -49,7 +56,7 @@ cmd_alias_dict = {
|
|||
def complete_command(arg):
|
||||
completions = []
|
||||
|
||||
for cmd, optarg in cmd_dict.iteritems():
|
||||
for cmd, optarg in cmd_opt_dict.iteritems():
|
||||
if cmd.startswith(arg):
|
||||
completions.append(cmd)
|
||||
|
||||
|
@ -117,15 +124,40 @@ def start_cmd(argv):
|
|||
# generic error code if not returned sooner
|
||||
return 1
|
||||
|
||||
def run_cmd(cmd, args = []):
|
||||
def run_cmd(cmd, argv = []):
|
||||
|
||||
options_pair = cmd_opt_dict[cmd]
|
||||
|
||||
options = global_options + options_pair[0]
|
||||
|
||||
options_long = []
|
||||
options_long.extend(global_options_long)
|
||||
options_long.extend(options_pair[1])
|
||||
|
||||
opts, args = getopt(argv, options, options_long)
|
||||
|
||||
verbose = False
|
||||
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
|
||||
optarg_data = cmd_dict[cmd]
|
||||
handler = commands.CommandHandler(args, optarg_data)
|
||||
handler = commands.CommandHandler(argv, opts, args)
|
||||
handler.verbose = verbose
|
||||
|
||||
# use reflection to get the function pointer
|
||||
cmd_func = getattr(handler, cmd)
|
||||
cmd_func()
|
||||
|
||||
try:
|
||||
cmd_func()
|
||||
except Exception as ex:
|
||||
if not verbose:
|
||||
# print friendly error for users
|
||||
print 'Error:',ex
|
||||
else:
|
||||
# if user wants to be verbose let python do it's thing
|
||||
raise
|
||||
|
||||
def main(argv):
|
||||
|
||||
|
|
Loading…
Reference in New Issue