Mercurial > parpg-core
comparison 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 |
comparison
equal
deleted
inserted
replaced
0:1fd2201f5c36 | 2:e2a8e3805b04 |
---|---|
1 import sys | |
2 import os | |
3 import platform | |
4 import compileall | |
5 import fnmatch | |
6 from collections import Sequence | |
7 from multiprocessing import cpu_count | |
8 | |
9 def InstallChmod(env, dest, source, mode): | |
10 targets = env.Install(dest, source) | |
11 for target in targets: | |
12 env.AddPostAction(target, Chmod(target, mode)) | |
13 return targets | |
14 | |
15 def InstallExecutable(env, dest, source): | |
16 return env.InstallChmod(dest, source, mode=0755) | |
17 | |
18 def InstallReadOnly(env, dest, source): | |
19 if not isinstance(source, Sequence): | |
20 source = [source] | |
21 targets = [] | |
22 for entry in map(Entry, source): | |
23 entry.disambiguate() | |
24 if entry.isdir(): | |
25 target = env.InstallChmod(dest, entry, mode=0755) | |
26 elif entry.isfile(): | |
27 target = env.InstallChmod(dest, entry, mode=0644) | |
28 else: | |
29 # Something really weird happened and entry is not a Dir or a | |
30 # File... (Note: Yes this can happen!) | |
31 error_message = \ | |
32 'expected entry to be a Dir or a File, but got {0!r}' | |
33 raise ValueError(error_message.format(entry)) | |
34 targets.append(target) | |
35 return targets | |
36 | |
37 def InstallPyPackages(env, dest, source, compile=True): | |
38 # Remove all existing *.pyc and *.pyo files for a sanitary install | |
39 # environment. | |
40 def _remove_compiled_modules(path): | |
41 for dir_path, dir_names, file_names in os.walk(path): | |
42 for file_name in fnmatch.filter(file_names, '*.py[co]'): | |
43 file_path = os.path.join(dir_path, file_name) | |
44 os.remove(file_path) | |
45 | |
46 def _add_targets(path): | |
47 for dir_path, dir_names, file_names in os.walk(path): | |
48 for file_name in fnmatch.filter(file_names, '*.py[co]'): | |
49 file_path = os.path.join(dir_path, file_name) | |
50 env.Clean(path, file_path) | |
51 source_file_path = file_path.rstrip('oc') | |
52 env.Depends(file_path, source_file_path) | |
53 | |
54 if not isinstance(source, Sequence): | |
55 source = [source] | |
56 for dir in source: | |
57 _remove_compiled_modules(str(dir)) | |
58 if compile: | |
59 compileall.compile_dir(str(dir), ddir=str(dest), force=True) | |
60 _add_targets(str(dir)) | |
61 targets = env.InstallReadOnly(dest, source) | |
62 return targets | |
63 | |
64 AddMethod(Environment, InstallChmod) | |
65 AddMethod(Environment, InstallExecutable) | |
66 AddMethod(Environment, InstallReadOnly) | |
67 AddMethod(Environment, InstallPyPackages) | |
68 | |
69 EnsurePythonVersion(2, 6) | |
70 | |
71 AddOption( | |
72 '--stand-alone', | |
73 dest='stand_alone', | |
74 action='store_true', | |
75 default=False, | |
76 help='install the entire program under installation prefix instead of in ' | |
77 'various system folders' | |
78 ) | |
79 AddOption( | |
80 '--no-compile', | |
81 dest='compile', | |
82 action='store_false', | |
83 default=True, | |
84 help='don\'t compile any Python modules into .pyc files', | |
85 ) | |
86 SetOption('num_jobs', cpu_count()) | |
87 | |
88 def is_abs_path(key, val, env): | |
89 if not os.path.isabs(val): | |
90 error_message = '${key} must be an absolute path' | |
91 raise ValueError(error_message.format(key=key)) | |
92 env[key] = os.path.normpath(val) | |
93 | |
94 variables = Variables() | |
95 # NOTE M. George Hansen 2011-05-13: Path variables are based on the GNU | |
96 # standards as defined at http://www.gnu.org/prep/standards/html_node/Directory-Variables.html | |
97 | |
98 # Platform-specific variable defaults. | |
99 # FIXME M. George Hansen 2011-05-12: Define the MacOS-specific | |
100 # environmental variables (and check version...) | |
101 platform_name = platform.system() | |
102 if platform_name in ['Linux', 'MacOS']: | |
103 if GetOption('stand_alone'): | |
104 PREFIX_DEFAULT = '/opt' | |
105 else: | |
106 PREFIX_DEFAULT = '/usr/local' | |
107 BIN_DIR_DEFAULT = '$EXEC_PREFIX/bin' | |
108 DATA_ROOT_DIR_DEFAULT = '$PREFIX/share/$PROJECT_NAME' | |
109 SYS_CONF_DIR_DEFAULT = '$PREFIX/etc/$PROJECT_NAME' | |
110 INCLUDE_DIR_DEFAULT = '$PREFIX/include/$PROJECT_NAME' | |
111 DOC_DIR_DEFAULT = '$DATA_ROOT_DIR/doc/$PROJECT_NAME' | |
112 LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib' | |
113 dist_name, dist_version, dist_id = \ | |
114 platform.linux_distribution(full_distribution_name=False) | |
115 if dist_name in ['debian', 'Ubuntu']: | |
116 # Debian uses dist-packages instead of site-packages for Python | |
117 # versions > 2.5. | |
118 PY_LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib/python$PY_VERSION_SHORT/' \ | |
119 'dist-packages' | |
120 else: | |
121 PY_LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib/python$PY_VERSION_SHORT/' \ | |
122 'site-packages' | |
123 elif platform_name == 'Windows': | |
124 try: | |
125 PREFIX_DEFAULT = os.environ['ProgramFiles'] + r'\$PROGRAM_NAME' | |
126 except KeyError: | |
127 PREFIX_DEFAULT = '' | |
128 error_message = '%ProgramFiles% environmental variable is not ' \ | |
129 'set, unable to determine path to Program Files ' \ | |
130 'folder (use --prefix to override)' | |
131 raise SConfWarning(error_message) | |
132 BIN_DIR_DEFAULT = '$EXEC_PREFIX' | |
133 DATA_ROOT_DIR_DEFAULT = '$PREFIX/data' | |
134 SYS_CONF_DIR_DEFAULT = '$PREFIX/config' | |
135 INCLUDE_DIR_DEFAULT = '$PREFIX/include' | |
136 DOC_DIR_DEFAULT = '$PREFIX/doc/' | |
137 LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib' | |
138 PY_LIB_DIR_DEFAULT = '$EXEC_PREFIX/lib' | |
139 if GetOption('stand_alone'): | |
140 PY_LIB_DIR_DEFAULT = '$PREFIX/lib' | |
141 else: | |
142 python_prefix = sys.prefix | |
143 # FIXME M. George Hansen 2011-05-12: Does sys.prefix include the | |
144 # PythonX.Y part on Windows? | |
145 PY_LIB_DIR_DEFAULT = \ | |
146 os.path.join(python_prefix, 'Lib', 'site-packages') | |
147 | |
148 # Platform-independant variables: | |
149 variables.AddVariables( | |
150 PathVariable( | |
151 'PREFIX', | |
152 'directory under which most or all of the program components should ' | |
153 'be installed', | |
154 PREFIX_DEFAULT, | |
155 is_abs_path, | |
156 ), | |
157 PathVariable( | |
158 'EXEC_PREFIX', | |
159 'directory under which machine-specific compiled libraries and ' | |
160 'objects should be installed', | |
161 '$PREFIX', | |
162 is_abs_path, | |
163 ), | |
164 PathVariable( | |
165 'BIN_DIR', | |
166 'directory where program executables should be installed', | |
167 BIN_DIR_DEFAULT, | |
168 is_abs_path, | |
169 ), | |
170 PathVariable( | |
171 'DATA_ROOT_DIR', | |
172 'directory under which read-only, architecture-independant data files ' | |
173 'should be installed', | |
174 DATA_ROOT_DIR_DEFAULT, | |
175 is_abs_path, | |
176 ), | |
177 PathVariable( | |
178 'DATA_DIR', | |
179 'directory where read-only, architecture-independant data files ' | |
180 'should be installed', | |
181 '$DATA_ROOT_DIR', | |
182 is_abs_path, | |
183 ), | |
184 PathVariable( | |
185 'SYS_CONF_DIR', | |
186 'directory where read-only, machine-specific data files should be ' | |
187 'installed', | |
188 SYS_CONF_DIR_DEFAULT, | |
189 is_abs_path, | |
190 ), | |
191 PathVariable( | |
192 'INCLUDE_DIR', | |
193 'directory where C/C++ header files should be installed', | |
194 INCLUDE_DIR_DEFAULT, | |
195 is_abs_path, | |
196 ), | |
197 PathVariable( | |
198 'DOC_DIR', | |
199 'directory where program documentation should be installed', | |
200 DOC_DIR_DEFAULT, | |
201 is_abs_path, | |
202 ), | |
203 PathVariable( | |
204 'LIB_DIR', | |
205 'directory where platform-dependant, compiled library and object ' | |
206 'files should be installed', | |
207 LIB_DIR_DEFAULT, | |
208 is_abs_path, | |
209 ), | |
210 PathVariable( | |
211 'PY_LIB_DIR', | |
212 'directory where pure Python modules and packages should be installed', | |
213 PY_LIB_DIR_DEFAULT, | |
214 is_abs_path, | |
215 ), | |
216 PathVariable( | |
217 'INCLUDE_DIR', | |
218 'directory where C/C++ header files should be installed', | |
219 INCLUDE_DIR_DEFAULT, | |
220 is_abs_path, | |
221 ), | |
222 ) | |
223 | |
224 platform_name = platform.system() | |
225 python_version_tuple = platform.python_version_tuple() | |
226 | |
227 environment = Environment( | |
228 tools=['default', 'textfile', 'packaging'], | |
229 variables=variables, | |
230 PROJECT_NAME='parpg', | |
231 PROJECT_VERSION_MAJOR=0, | |
232 PROJECT_VERSION_MINOR=2, | |
233 PROJECT_VERSION_PATCH=0, | |
234 PROJECT_VERSION_SHORT='$PROJECT_VERSION_MAJOR.$PROJECT_VERSION_MAJOR', | |
235 PROJECT_VERSION_LONG='$PROJECT_VERSION_MAJOR.$PROJECT_VERSION_MINOR.' | |
236 '$PROJECT_VERSION_PATCH', | |
237 PYTHON=sys.executable, | |
238 PY_VERSION_SHORT='.'.join(python_version_tuple[:-1]), | |
239 PY_VERSION_LONG='.'.join(python_version_tuple), | |
240 PY_PACKAGES=[], | |
241 CONFIG_FILES=[], | |
242 DATA_FILES=[], | |
243 EXECUTABLES=[], | |
244 ) | |
245 Help(variables.GenerateHelpText(environment)) | |
246 | |
247 config_dict = [('@{0}@'.format(key), environment.Dictionary()[key]) for key in | |
248 ('PREFIX', 'LIB_DIR', 'PY_LIB_DIR', 'BIN_DIR', 'SYS_CONF_DIR', | |
249 'DATA_DIR', 'PYTHON')] | |
250 | |
251 environment['PY_PACKAGES'] += [ | |
252 Dir('src/parpg'), | |
253 ] | |
254 config_file_template = File('system.cfg.in') | |
255 subst_config_file = environment.Substfile(config_file_template, | |
256 SUBST_DICT=config_dict) | |
257 environment['CONFIG_FILES'] += [subst_config_file] | |
258 environment['DATA_FILES'] += Glob('data/*') | |
259 # TODO M. George Hansen 2011-05-12: Implement windows executable. | |
260 executable_template = File('bin/unix/parpg.in') | |
261 subst_executable = environment.Substfile(executable_template, | |
262 SUBST_DICT=config_dict) | |
263 environment['EXECUTABLES'] += [subst_executable] | |
264 | |
265 sources = environment.InstallPyPackages( | |
266 '$PY_LIB_DIR', | |
267 environment['PY_PACKAGES'], | |
268 compile=GetOption('compile'), | |
269 ) | |
270 config_files = environment.InstallChmod( | |
271 '$SYS_CONF_DIR', | |
272 environment['CONFIG_FILES'], | |
273 mode=0755, | |
274 ) | |
275 Requires(config_files, subst_config_file) | |
276 data_files = environment.InstallReadOnly( | |
277 '$DATA_DIR', | |
278 environment['DATA_FILES'], | |
279 ) | |
280 executables = environment.InstallExecutable( | |
281 '$BIN_DIR', | |
282 environment['EXECUTABLES'], | |
283 ) | |
284 Requires(executables, subst_executable) | |
285 | |
286 # TODO M. George Hansen 2011-05-12: Implement package builder. | |
287 #package = environment.Package( | |
288 # NAME='parpg', | |
289 # VERSION='0.2.0', | |
290 # PACKAGEVERSION=0, | |
291 # LICENSE='gpl', | |
292 # SUMMARY='', | |
293 # DESCRIPTION='', | |
294 # X_RPM_GROUP='Application/parpg', | |
295 #) | |
296 | |
297 Default([sources, config_files, data_files, executables]) | |
298 Alias('install', [sources, config_files, data_files, executables]) |