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