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