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