Mercurial > parpg-core
diff SConstruct @ 2:e2a8e3805b04
Made parpg-core the main repository to pull from and build.
* Added parpg-assets as a subrepo under the data folder.
* Moved the SConstruct script into parpg-core and modified it to build and install parpg-assets as well.
* Made a few minor changes to the SConstruct file from the defunct parpg-main repository.
* Modified unix parpg executable script template to be more forgiving of installing the parpg Python package outside of PYTHONPATH.
* Updated the .hgignore file to include temporary SCons files.
author | M. George Hansen <technopolitica@gmail.com> |
---|---|
date | Sun, 15 May 2011 14:51:41 -0700 |
parents | |
children | 33684971cdb1 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SConstruct Sun May 15 14:51:41 2011 -0700 @@ -0,0 +1,298 @@ +import sys +import os +import platform +import compileall +import fnmatch +from collections import Sequence +from multiprocessing import cpu_count + +def InstallChmod(env, dest, source, mode): + targets = env.Install(dest, source) + for target in targets: + env.AddPostAction(target, Chmod(target, mode)) + return targets + +def InstallExecutable(env, dest, source): + return env.InstallChmod(dest, source, mode=0755) + +def InstallReadOnly(env, dest, source): + if not isinstance(source, Sequence): + source = [source] + targets = [] + for entry in map(Entry, source): + entry.disambiguate() + if entry.isdir(): + target = env.InstallChmod(dest, entry, mode=0755) + elif entry.isfile(): + target = env.InstallChmod(dest, entry, mode=0644) + else: + # Something really weird happened and entry is not a Dir or a + # File... (Note: Yes this can happen!) + error_message = \ + 'expected entry to be a Dir or a File, but got {0!r}' + raise ValueError(error_message.format(entry)) + targets.append(target) + return targets + +def InstallPyPackages(env, dest, source, compile=True): + # Remove all existing *.pyc and *.pyo files for a sanitary install + # environment. + def _remove_compiled_modules(path): + for dir_path, dir_names, file_names in os.walk(path): + for file_name in fnmatch.filter(file_names, '*.py[co]'): + file_path = os.path.join(dir_path, file_name) + os.remove(file_path) + + def _add_targets(path): + for dir_path, dir_names, file_names in os.walk(path): + for file_name in fnmatch.filter(file_names, '*.py[co]'): + file_path = os.path.join(dir_path, file_name) + env.Clean(path, file_path) + source_file_path = file_path.rstrip('oc') + env.Depends(file_path, source_file_path) + + if not isinstance(source, Sequence): + source = [source] + for dir in source: + _remove_compiled_modules(str(dir)) + if compile: + compileall.compile_dir(str(dir), ddir=str(dest), force=True) + _add_targets(str(dir)) + targets = env.InstallReadOnly(dest, source) + return targets + +AddMethod(Environment, InstallChmod) +AddMethod(Environment, InstallExecutable) +AddMethod(Environment, InstallReadOnly) +AddMethod(Environment, InstallPyPackages) + +EnsurePythonVersion(2, 6) + +AddOption( + '--stand-alone', + dest='stand_alone', + action='store_true', + default=False, + help='install the entire program under installation prefix instead of in ' + 'various system folders' +) +AddOption( + '--no-compile', + dest='compile', + action='store_false', + default=True, + help='don\'t compile any Python modules into .pyc files', +) +SetOption('num_jobs', cpu_count()) + +def is_abs_path(key, val, env): + if not os.path.isabs(val): + error_message = '${key} must be an absolute path' + raise ValueError(error_message.format(key=key)) + env[key] = os.path.normpath(val) + +variables = Variables() +# NOTE M. George Hansen 2011-05-13: Path variables are based on the GNU +# standards as defined at http://www.gnu.org/prep/standards/html_node/Directory-Variables.html + +# Platform-specific variable defaults. +# FIXME M. George Hansen 2011-05-12: Define the MacOS-specific +# environmental variables (and check version...) +platform_name = platform.system() +if platform_name in ['Linux', 'MacOS']: + if GetOption('stand_alone'): + PREFIX_DEFAULT = '/opt' + else: + PREFIX_DEFAULT = '/usr/local' + BIN_DIR_DEFAULT = '$EXEC_PREFIX/bin' + DATA_ROOT_DIR_DEFAULT = '$PREFIX/share/$PROJECT_NAME' + SYS_CONF_DIR_DEFAULT = '$PREFIX/etc/$PROJECT_NAME' + INCLUDE_DIR_DEFAULT = '$PREFIX/include/$PROJECT_NAME' + DOC_DIR_DEFAULT = '$DATA_ROOT_DIR/doc/$PROJECT_NAME' + LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib' + dist_name, dist_version, dist_id = \ + platform.linux_distribution(full_distribution_name=False) + if dist_name in ['debian', 'Ubuntu']: + # Debian uses dist-packages instead of site-packages for Python + # versions > 2.5. + PY_LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib/python$PY_VERSION_SHORT/' \ + 'dist-packages' + else: + PY_LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib/python$PY_VERSION_SHORT/' \ + 'site-packages' +elif platform_name == 'Windows': + try: + PREFIX_DEFAULT = os.environ['ProgramFiles'] + r'\$PROGRAM_NAME' + except KeyError: + PREFIX_DEFAULT = '' + error_message = '%ProgramFiles% environmental variable is not ' \ + 'set, unable to determine path to Program Files ' \ + 'folder (use --prefix to override)' + raise SConfWarning(error_message) + BIN_DIR_DEFAULT = '$EXEC_PREFIX' + DATA_ROOT_DIR_DEFAULT = '$PREFIX/data' + SYS_CONF_DIR_DEFAULT = '$PREFIX/config' + INCLUDE_DIR_DEFAULT = '$PREFIX/include' + DOC_DIR_DEFAULT = '$PREFIX/doc/' + LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib' + PY_LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib' + if GetOption('stand_alone'): + PY_LIB_DIR_DEFAULT = '$PREFIX/lib' + else: + python_prefix = sys.prefix + # FIXME M. George Hansen 2011-05-12: Does sys.prefix include the + # PythonX.Y part on Windows? + PY_LIB_DIR_DEFAULT = \ + os.path.join(python_prefix, 'Lib', 'site-packages') + +# Platform-independant variables: +variables.AddVariables( + PathVariable( + 'PREFIX', + 'directory under which most or all of the program components should ' + 'be installed', + PREFIX_DEFAULT, + is_abs_path, + ), + PathVariable( + 'EXEC_PREFIX', + 'directory under which machine-specific compiled libraries and ' + 'objects should be installed', + '$PREFIX', + is_abs_path, + ), + PathVariable( + 'BIN_DIR', + 'directory where program executables should be installed', + BIN_DIR_DEFAULT, + is_abs_path, + ), + PathVariable( + 'DATA_ROOT_DIR', + 'directory under which read-only, architecture-independant data files ' + 'should be installed', + DATA_ROOT_DIR_DEFAULT, + is_abs_path, + ), + PathVariable( + 'DATA_DIR', + 'directory where read-only, architecture-independant data files ' + 'should be installed', + '$DATA_ROOT_DIR', + is_abs_path, + ), + PathVariable( + 'SYS_CONF_DIR', + 'directory where read-only, machine-specific data files should be ' + 'installed', + SYS_CONF_DIR_DEFAULT, + is_abs_path, + ), + PathVariable( + 'INCLUDE_DIR', + 'directory where C/C++ header files should be installed', + INCLUDE_DIR_DEFAULT, + is_abs_path, + ), + PathVariable( + 'DOC_DIR', + 'directory where program documentation should be installed', + DOC_DIR_DEFAULT, + is_abs_path, + ), + PathVariable( + 'LIB_DIR', + 'directory where platform-dependant, compiled library and object ' + 'files should be installed', + LIB_DIR_DEFAULT, + is_abs_path, + ), + PathVariable( + 'PY_LIB_DIR', + 'directory where pure Python modules and packages should be installed', + PY_LIB_DIR_DEFAULT, + is_abs_path, + ), + PathVariable( + 'INCLUDE_DIR', + 'directory where C/C++ header files should be installed', + INCLUDE_DIR_DEFAULT, + is_abs_path, + ), +) + +platform_name = platform.system() +python_version_tuple = platform.python_version_tuple() + +environment = Environment( + tools=['default', 'textfile', 'packaging'], + variables=variables, + PROJECT_NAME='parpg', + PROJECT_VERSION_MAJOR=0, + PROJECT_VERSION_MINOR=2, + PROJECT_VERSION_PATCH=0, + PROJECT_VERSION_SHORT='$PROJECT_VERSION_MAJOR.$PROJECT_VERSION_MAJOR', + PROJECT_VERSION_LONG='$PROJECT_VERSION_MAJOR.$PROJECT_VERSION_MINOR.' + '$PROJECT_VERSION_PATCH', + PYTHON=sys.executable, + PY_VERSION_SHORT='.'.join(python_version_tuple[:-1]), + PY_VERSION_LONG='.'.join(python_version_tuple), + PY_PACKAGES=[], + CONFIG_FILES=[], + DATA_FILES=[], + EXECUTABLES=[], +) +Help(variables.GenerateHelpText(environment)) + +config_dict = [('@{0}@'.format(key), environment.Dictionary()[key]) for key in + ('PREFIX', 'LIB_DIR', 'PY_LIB_DIR', 'BIN_DIR', 'SYS_CONF_DIR', + 'DATA_DIR', 'PYTHON')] + +environment['PY_PACKAGES'] += [ + Dir('src/parpg'), +] +config_file_template = File('system.cfg.in') +subst_config_file = environment.Substfile(config_file_template, + SUBST_DICT=config_dict) +environment['CONFIG_FILES'] += [subst_config_file] +environment['DATA_FILES'] += Glob('data/*') +# TODO M. George Hansen 2011-05-12: Implement windows executable. +executable_template = File('bin/unix/parpg.in') +subst_executable = environment.Substfile(executable_template, + SUBST_DICT=config_dict) +environment['EXECUTABLES'] += [subst_executable] + +sources = environment.InstallPyPackages( + '$PY_LIB_DIR', + environment['PY_PACKAGES'], + compile=GetOption('compile'), +) +config_files = environment.InstallChmod( + '$SYS_CONF_DIR', + environment['CONFIG_FILES'], + mode=0755, +) +Requires(config_files, subst_config_file) +data_files = environment.InstallReadOnly( + '$DATA_DIR', + environment['DATA_FILES'], +) +executables = environment.InstallExecutable( + '$BIN_DIR', + environment['EXECUTABLES'], +) +Requires(executables, subst_executable) + +# TODO M. George Hansen 2011-05-12: Implement package builder. +#package = environment.Package( +# NAME='parpg', +# VERSION='0.2.0', +# PACKAGEVERSION=0, +# LICENSE='gpl', +# SUMMARY='', +# DESCRIPTION='', +# X_RPM_GROUP='Application/parpg', +#) + +Default([sources, config_files, data_files, executables]) +Alias('install', [sources, config_files, data_files, executables])