##// END OF EJS Templates
fix system->os.system typo...
MinRK -
Show More
@@ -1,428 +1,428 b''
1 1 # encoding: utf-8
2 2 """
3 3 This module defines the things that are used in setup.py for building IPython
4 4
5 5 This includes:
6 6
7 7 * The basic arguments to setup
8 8 * Functions for finding things like packages, package data, etc.
9 9 * A function for checking dependencies.
10 10 """
11 11 from __future__ import print_function
12 12
13 13 #-------------------------------------------------------------------------------
14 14 # Copyright (C) 2008 The IPython Development Team
15 15 #
16 16 # Distributed under the terms of the BSD License. The full license is in
17 17 # the file COPYING, distributed as part of this software.
18 18 #-------------------------------------------------------------------------------
19 19
20 20 #-------------------------------------------------------------------------------
21 21 # Imports
22 22 #-------------------------------------------------------------------------------
23 23 import os
24 24 import sys
25 25
26 26 try:
27 27 from configparser import ConfigParser
28 28 except:
29 29 from ConfigParser import ConfigParser
30 30 from distutils.command.build_py import build_py
31 31 from glob import glob
32 32
33 33 from setupext import install_data_ext
34 34
35 35 #-------------------------------------------------------------------------------
36 36 # Useful globals and utility functions
37 37 #-------------------------------------------------------------------------------
38 38
39 39 # A few handy globals
40 40 isfile = os.path.isfile
41 41 pjoin = os.path.join
42 42
43 43 def oscmd(s):
44 44 print(">", s)
45 45 os.system(s)
46 46
47 47 try:
48 48 execfile
49 49 except NameError:
50 50 def execfile(fname, globs, locs=None):
51 51 locs = locs or globs
52 52 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
53 53
54 54 # A little utility we'll need below, since glob() does NOT allow you to do
55 55 # exclusion on multiple endings!
56 56 def file_doesnt_endwith(test,endings):
57 57 """Return true if test is a file and its name does NOT end with any
58 58 of the strings listed in endings."""
59 59 if not isfile(test):
60 60 return False
61 61 for e in endings:
62 62 if test.endswith(e):
63 63 return False
64 64 return True
65 65
66 66 #---------------------------------------------------------------------------
67 67 # Basic project information
68 68 #---------------------------------------------------------------------------
69 69
70 70 # release.py contains version, authors, license, url, keywords, etc.
71 71 execfile(pjoin('IPython','core','release.py'), globals())
72 72
73 73 # Create a dict with the basic information
74 74 # This dict is eventually passed to setup after additional keys are added.
75 75 setup_args = dict(
76 76 name = name,
77 77 version = version,
78 78 description = description,
79 79 long_description = long_description,
80 80 author = author,
81 81 author_email = author_email,
82 82 url = url,
83 83 download_url = download_url,
84 84 license = license,
85 85 platforms = platforms,
86 86 keywords = keywords,
87 87 classifiers = classifiers,
88 88 cmdclass = {'install_data': install_data_ext},
89 89 )
90 90
91 91
92 92 #---------------------------------------------------------------------------
93 93 # Find packages
94 94 #---------------------------------------------------------------------------
95 95
96 96 def find_packages():
97 97 """
98 98 Find all of IPython's packages.
99 99 """
100 100 excludes = ['deathrow']
101 101 packages = []
102 102 for dir,subdirs,files in os.walk('IPython'):
103 103 package = dir.replace(os.path.sep, '.')
104 104 if any([ package.startswith('IPython.'+exc) for exc in excludes ]):
105 105 # package is to be excluded (e.g. deathrow)
106 106 continue
107 107 if '__init__.py' not in files:
108 108 # not a package
109 109 continue
110 110 packages.append(package)
111 111 return packages
112 112
113 113 #---------------------------------------------------------------------------
114 114 # Find package data
115 115 #---------------------------------------------------------------------------
116 116
117 117 def find_package_data():
118 118 """
119 119 Find IPython's package_data.
120 120 """
121 121 # This is not enough for these things to appear in an sdist.
122 122 # We need to muck with the MANIFEST to get this to work
123 123
124 124 # exclude static things that we don't ship (e.g. mathjax)
125 125 excludes = ['mathjax']
126 126
127 127 # add 'static/' prefix to exclusions, and tuplify for use in startswith
128 128 excludes = tuple([os.path.join('static', ex) for ex in excludes])
129 129
130 130 # walk notebook resources:
131 131 cwd = os.getcwd()
132 132 os.chdir(os.path.join('IPython', 'frontend', 'html', 'notebook'))
133 133 static_walk = list(os.walk('static'))
134 134 os.chdir(cwd)
135 135 static_data = []
136 136 for parent, dirs, files in static_walk:
137 137 if parent.startswith(excludes):
138 138 continue
139 139 for f in files:
140 140 static_data.append(os.path.join(parent, f))
141 141
142 142 package_data = {
143 143 'IPython.config.profile' : ['README*', '*/*.py'],
144 144 'IPython.testing' : ['*.txt'],
145 145 'IPython.frontend.html.notebook' : ['templates/*'] + static_data,
146 146 'IPython.frontend.qt.console' : ['resources/icon/*.svg'],
147 147 }
148 148 return package_data
149 149
150 150
151 151 #---------------------------------------------------------------------------
152 152 # Find data files
153 153 #---------------------------------------------------------------------------
154 154
155 155 def make_dir_struct(tag,base,out_base):
156 156 """Make the directory structure of all files below a starting dir.
157 157
158 158 This is just a convenience routine to help build a nested directory
159 159 hierarchy because distutils is too stupid to do this by itself.
160 160
161 161 XXX - this needs a proper docstring!
162 162 """
163 163
164 164 # we'll use these a lot below
165 165 lbase = len(base)
166 166 pathsep = os.path.sep
167 167 lpathsep = len(pathsep)
168 168
169 169 out = []
170 170 for (dirpath,dirnames,filenames) in os.walk(base):
171 171 # we need to strip out the dirpath from the base to map it to the
172 172 # output (installation) path. This requires possibly stripping the
173 173 # path separator, because otherwise pjoin will not work correctly
174 174 # (pjoin('foo/','/bar') returns '/bar').
175 175
176 176 dp_eff = dirpath[lbase:]
177 177 if dp_eff.startswith(pathsep):
178 178 dp_eff = dp_eff[lpathsep:]
179 179 # The output path must be anchored at the out_base marker
180 180 out_path = pjoin(out_base,dp_eff)
181 181 # Now we can generate the final filenames. Since os.walk only produces
182 182 # filenames, we must join back with the dirpath to get full valid file
183 183 # paths:
184 184 pfiles = [pjoin(dirpath,f) for f in filenames]
185 185 # Finally, generate the entry we need, which is a pari of (output
186 186 # path, files) for use as a data_files parameter in install_data.
187 187 out.append((out_path, pfiles))
188 188
189 189 return out
190 190
191 191
192 192 def find_data_files():
193 193 """
194 194 Find IPython's data_files.
195 195
196 196 Most of these are docs.
197 197 """
198 198
199 199 docdirbase = pjoin('share', 'doc', 'ipython')
200 200 manpagebase = pjoin('share', 'man', 'man1')
201 201
202 202 # Simple file lists can be made by hand
203 203 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
204 204 if not manpages:
205 205 # When running from a source tree, the manpages aren't gzipped
206 206 manpages = filter(isfile, glob(pjoin('docs','man','*.1')))
207 207 igridhelpfiles = filter(isfile,
208 208 glob(pjoin('IPython','extensions','igrid_help.*')))
209 209
210 210 # For nested structures, use the utility above
211 211 example_files = make_dir_struct(
212 212 'data',
213 213 pjoin('docs','examples'),
214 214 pjoin(docdirbase,'examples')
215 215 )
216 216 manual_files = make_dir_struct(
217 217 'data',
218 218 pjoin('docs','html'),
219 219 pjoin(docdirbase,'manual')
220 220 )
221 221
222 222 # And assemble the entire output list
223 223 data_files = [ (manpagebase, manpages),
224 224 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
225 225 ] + manual_files + example_files
226 226
227 227 return data_files
228 228
229 229
230 230 def make_man_update_target(manpage):
231 231 """Return a target_update-compliant tuple for the given manpage.
232 232
233 233 Parameters
234 234 ----------
235 235 manpage : string
236 236 Name of the manpage, must include the section number (trailing number).
237 237
238 238 Example
239 239 -------
240 240
241 241 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
242 242 ('docs/man/ipython.1.gz',
243 243 ['docs/man/ipython.1'],
244 244 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
245 245 """
246 246 man_dir = pjoin('docs', 'man')
247 247 manpage_gz = manpage + '.gz'
248 248 manpath = pjoin(man_dir, manpage)
249 249 manpath_gz = pjoin(man_dir, manpage_gz)
250 250 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
251 251 locals() )
252 252 return (manpath_gz, [manpath], gz_cmd)
253 253
254 254 # The two functions below are copied from IPython.utils.path, so we don't need
255 255 # to import IPython during setup, which fails on Python 3.
256 256
257 257 def target_outdated(target,deps):
258 258 """Determine whether a target is out of date.
259 259
260 260 target_outdated(target,deps) -> 1/0
261 261
262 262 deps: list of filenames which MUST exist.
263 263 target: single filename which may or may not exist.
264 264
265 265 If target doesn't exist or is older than any file listed in deps, return
266 266 true, otherwise return false.
267 267 """
268 268 try:
269 269 target_time = os.path.getmtime(target)
270 270 except os.error:
271 271 return 1
272 272 for dep in deps:
273 273 dep_time = os.path.getmtime(dep)
274 274 if dep_time > target_time:
275 275 #print "For target",target,"Dep failed:",dep # dbg
276 276 #print "times (dep,tar):",dep_time,target_time # dbg
277 277 return 1
278 278 return 0
279 279
280 280
281 281 def target_update(target,deps,cmd):
282 282 """Update a target with a given command given a list of dependencies.
283 283
284 284 target_update(target,deps,cmd) -> runs cmd if target is outdated.
285 285
286 286 This is just a wrapper around target_outdated() which calls the given
287 287 command if target is outdated."""
288 288
289 289 if target_outdated(target,deps):
290 system(cmd)
290 os.system(cmd)
291 291
292 292 #---------------------------------------------------------------------------
293 293 # Find scripts
294 294 #---------------------------------------------------------------------------
295 295
296 296 def find_scripts(entry_points=False, suffix=''):
297 297 """Find IPython's scripts.
298 298
299 299 if entry_points is True:
300 300 return setuptools entry_point-style definitions
301 301 else:
302 302 return file paths of plain scripts [default]
303 303
304 304 suffix is appended to script names if entry_points is True, so that the
305 305 Python 3 scripts get named "ipython3" etc.
306 306 """
307 307 if entry_points:
308 308 console_scripts = [s % suffix for s in [
309 309 'ipython%s = IPython.frontend.terminal.ipapp:launch_new_instance',
310 310 'pycolor%s = IPython.utils.PyColorize:main',
311 311 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
312 312 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
313 313 'iplogger%s = IPython.parallel.apps.iploggerapp:launch_new_instance',
314 314 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
315 315 'iptest%s = IPython.testing.iptest:main',
316 316 'irunner%s = IPython.lib.irunner:main'
317 317 ]]
318 318 gui_scripts = [s % suffix for s in [
319 319 'ipython%s-qtconsole = IPython.frontend.qt.console.qtconsoleapp:main',
320 320 ]]
321 321 scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
322 322 else:
323 323 parallel_scripts = pjoin('IPython','parallel','scripts')
324 324 main_scripts = pjoin('IPython','scripts')
325 325 scripts = [
326 326 pjoin(parallel_scripts, 'ipengine'),
327 327 pjoin(parallel_scripts, 'ipcontroller'),
328 328 pjoin(parallel_scripts, 'ipcluster'),
329 329 pjoin(parallel_scripts, 'iplogger'),
330 330 pjoin(main_scripts, 'ipython'),
331 331 pjoin(main_scripts, 'pycolor'),
332 332 pjoin(main_scripts, 'irunner'),
333 333 pjoin(main_scripts, 'iptest')
334 334 ]
335 335 return scripts
336 336
337 337 #---------------------------------------------------------------------------
338 338 # Verify all dependencies
339 339 #---------------------------------------------------------------------------
340 340
341 341 def check_for_dependencies():
342 342 """Check for IPython's dependencies.
343 343
344 344 This function should NOT be called if running under setuptools!
345 345 """
346 346 from setupext.setupext import (
347 347 print_line, print_raw, print_status,
348 348 check_for_sphinx, check_for_pygments,
349 349 check_for_nose, check_for_pexpect,
350 350 check_for_pyzmq, check_for_readline
351 351 )
352 352 print_line()
353 353 print_raw("BUILDING IPYTHON")
354 354 print_status('python', sys.version)
355 355 print_status('platform', sys.platform)
356 356 if sys.platform == 'win32':
357 357 print_status('Windows version', sys.getwindowsversion())
358 358
359 359 print_raw("")
360 360 print_raw("OPTIONAL DEPENDENCIES")
361 361
362 362 check_for_sphinx()
363 363 check_for_pygments()
364 364 check_for_nose()
365 365 check_for_pexpect()
366 366 check_for_pyzmq()
367 367 check_for_readline()
368 368
369 369 def record_commit_info(pkg_dir, build_cmd=build_py):
370 370 """ Return extended build command class for recording commit
371 371
372 372 The extended command tries to run git to find the current commit, getting
373 373 the empty string if it fails. It then writes the commit hash into a file
374 374 in the `pkg_dir` path, named ``.git_commit_info.ini``.
375 375
376 376 In due course this information can be used by the package after it is
377 377 installed, to tell you what commit it was installed from if known.
378 378
379 379 To make use of this system, you need a package with a .git_commit_info.ini
380 380 file - e.g. ``myproject/.git_commit_info.ini`` - that might well look like
381 381 this::
382 382
383 383 # This is an ini file that may contain information about the code state
384 384 [commit hash]
385 385 # The line below may contain a valid hash if it has been substituted
386 386 # during 'git archive'
387 387 archive_subst_hash=$Format:%h$
388 388 # This line may be modified by the install process
389 389 install_hash=
390 390
391 391 The .git_commit_info file above is also designed to be used with git
392 392 substitution - so you probably also want a ``.gitattributes`` file in the
393 393 root directory of your working tree that contains something like this::
394 394
395 395 myproject/.git_commit_info.ini export-subst
396 396
397 397 That will cause the ``.git_commit_info.ini`` file to get filled in by ``git
398 398 archive`` - useful in case someone makes such an archive - for example with
399 399 via the github 'download source' button.
400 400
401 401 Although all the above will work as is, you might consider having something
402 402 like a ``get_info()`` function in your package to display the commit
403 403 information at the terminal. See the ``pkg_info.py`` module in the nipy
404 404 package for an example.
405 405 """
406 406 class MyBuildPy(build_cmd):
407 407 ''' Subclass to write commit data into installation tree '''
408 408 def run(self):
409 409 build_cmd.run(self)
410 410 import subprocess
411 411 proc = subprocess.Popen('git rev-parse --short HEAD',
412 412 stdout=subprocess.PIPE,
413 413 stderr=subprocess.PIPE,
414 414 shell=True)
415 415 repo_commit, _ = proc.communicate()
416 416 # We write the installation commit even if it's empty
417 417 cfg_parser = ConfigParser()
418 418 cfg_parser.read(pjoin(pkg_dir, '.git_commit_info.ini'))
419 419 if not cfg_parser.has_section('commit hash'):
420 420 # just in case the ini file is empty or doesn't exist, somehow
421 421 # we don't want the next line to raise
422 422 cfg_parser.add_section('commit hash')
423 423 cfg_parser.set('commit hash', 'install_hash', repo_commit.decode('ascii'))
424 424 out_pth = pjoin(self.build_lib, pkg_dir, '.git_commit_info.ini')
425 425 out_file = open(out_pth, 'wt')
426 426 cfg_parser.write(out_file)
427 427 out_file.close()
428 428 return MyBuildPy
General Comments 0
You need to be logged in to leave comments. Login now