##// END OF EJS Templates
Clean up entry point definition is setup.py.
epatters -
Show More
@@ -1,265 +1,261
1 1 #!/usr/bin/env python
2 2 # -*- coding: utf-8 -*-
3 3 """Setup script for IPython.
4 4
5 5 Under Posix environments it works like a typical setup.py script.
6 6 Under Windows, the command sdist is not supported, since IPython
7 7 requires utilities which are not available under Windows."""
8 8
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (c) 2008-2010, IPython Development Team.
11 11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
12 12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13 13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
14 14 #
15 15 # Distributed under the terms of the Modified BSD License.
16 16 #
17 17 # The full license is in the file COPYING.txt, distributed with this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Minimal Python version sanity check
22 22 #-----------------------------------------------------------------------------
23 23
24 24 import sys
25 25
26 26 # This check is also made in IPython/__init__, don't forget to update both when
27 27 # changing Python version requirements.
28 28 if sys.version[0:3] < '2.6':
29 29 error = """\
30 30 ERROR: 'IPython requires Python Version 2.6 or above.'
31 31 Exiting."""
32 32 print >> sys.stderr, error
33 33 sys.exit(1)
34 34
35 35 # At least we're on the python version we need, move on.
36 36
37 37 #-------------------------------------------------------------------------------
38 38 # Imports
39 39 #-------------------------------------------------------------------------------
40 40
41 41 # Stdlib imports
42 42 import os
43 43 import shutil
44 44
45 45 from glob import glob
46 46
47 47 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
48 48 # update it when the contents of directories change.
49 49 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
50 50
51 51 from distutils.core import setup
52 52
53 53 # Our own imports
54 54 from IPython.utils.path import target_update
55 55
56 56 from setupbase import (
57 57 setup_args,
58 58 find_packages,
59 59 find_package_data,
60 60 find_scripts,
61 find_gui_scripts,
62 61 find_data_files,
63 62 check_for_dependencies,
64 63 record_commit_info,
65 64 )
66 65 from setupext import setupext
67 66
68 67 isfile = os.path.isfile
69 68 pjoin = os.path.join
70 69
71 70 #-----------------------------------------------------------------------------
72 71 # Function definitions
73 72 #-----------------------------------------------------------------------------
74 73
75 74 def cleanup():
76 75 """Clean up the junk left around by the build process"""
77 76 if "develop" not in sys.argv:
78 77 try:
79 78 shutil.rmtree('ipython.egg-info')
80 79 except:
81 80 try:
82 81 os.unlink('ipython.egg-info')
83 82 except:
84 83 pass
85 84
86 85 #-------------------------------------------------------------------------------
87 86 # Handle OS specific things
88 87 #-------------------------------------------------------------------------------
89 88
90 89 if os.name == 'posix':
91 90 os_name = 'posix'
92 91 elif os.name in ['nt','dos']:
93 92 os_name = 'windows'
94 93 else:
95 94 print 'Unsupported operating system:',os.name
96 95 sys.exit(1)
97 96
98 97 # Under Windows, 'sdist' has not been supported. Now that the docs build with
99 98 # Sphinx it might work, but let's not turn it on until someone confirms that it
100 99 # actually works.
101 100 if os_name == 'windows' and 'sdist' in sys.argv:
102 101 print 'The sdist command is not available under Windows. Exiting.'
103 102 sys.exit(1)
104 103
105 104 #-------------------------------------------------------------------------------
106 105 # Things related to the IPython documentation
107 106 #-------------------------------------------------------------------------------
108 107
109 108 # update the manuals when building a source dist
110 109 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
111 110 import textwrap
112 111
113 112 # List of things to be updated. Each entry is a triplet of args for
114 113 # target_update()
115 114 to_update = [
116 115 # FIXME - Disabled for now: we need to redo an automatic way
117 116 # of generating the magic info inside the rst.
118 117 #('docs/magic.tex',
119 118 #['IPython/Magic.py'],
120 119 #"cd doc && ./update_magic.sh" ),
121 120
122 121 ('docs/man/ipcluster.1.gz',
123 122 ['docs/man/ipcluster.1'],
124 123 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
125 124
126 125 ('docs/man/ipcontroller.1.gz',
127 126 ['docs/man/ipcontroller.1'],
128 127 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
129 128
130 129 ('docs/man/ipengine.1.gz',
131 130 ['docs/man/ipengine.1'],
132 131 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
133 132
134 133 ('docs/man/ipython.1.gz',
135 134 ['docs/man/ipython.1'],
136 135 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
137 136
138 137 ('docs/man/ipython-wx.1.gz',
139 138 ['docs/man/ipython-wx.1'],
140 139 'cd docs/man && gzip -9c ipython-wx.1 > ipython-wx.1.gz'),
141 140
142 141 ('docs/man/ipythonx.1.gz',
143 142 ['docs/man/ipythonx.1'],
144 143 'cd docs/man && gzip -9c ipythonx.1 > ipythonx.1.gz'),
145 144
146 145 ('docs/man/irunner.1.gz',
147 146 ['docs/man/irunner.1'],
148 147 'cd docs/man && gzip -9c irunner.1 > irunner.1.gz'),
149 148
150 149 ('docs/man/pycolor.1.gz',
151 150 ['docs/man/pycolor.1'],
152 151 'cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz'),
153 152 ]
154 153
155 154 # Only build the docs if sphinx is present
156 155 try:
157 156 import sphinx
158 157 except ImportError:
159 158 pass
160 159 else:
161 160 # The Makefile calls the do_sphinx scripts to build html and pdf, so
162 161 # just one target is enough to cover all manual generation
163 162
164 163 # First, compute all the dependencies that can force us to rebuild the
165 164 # docs. Start with the main release file that contains metadata
166 165 docdeps = ['IPython/core/release.py']
167 166 # Inculde all the reST sources
168 167 pjoin = os.path.join
169 168 for dirpath,dirnames,filenames in os.walk('docs/source'):
170 169 if dirpath in ['_static','_templates']:
171 170 continue
172 171 docdeps += [ pjoin(dirpath,f) for f in filenames
173 172 if f.endswith('.txt') ]
174 173 # and the examples
175 174 for dirpath,dirnames,filenames in os.walk('docs/example'):
176 175 docdeps += [ pjoin(dirpath,f) for f in filenames
177 176 if not f.endswith('~') ]
178 177 # then, make them all dependencies for the main PDF (the html will get
179 178 # auto-generated as well).
180 179 to_update.append(
181 180 ('docs/dist/ipython.pdf',
182 181 docdeps,
183 182 "cd docs && make dist")
184 183 )
185 184
186 185 [ target_update(*t) for t in to_update ]
187 186
188 187 #---------------------------------------------------------------------------
189 188 # Find all the packages, package data, and data_files
190 189 #---------------------------------------------------------------------------
191 190
192 191 packages = find_packages()
193 192 package_data = find_package_data()
194 193 data_files = find_data_files()
195 194
196 195 #---------------------------------------------------------------------------
197 196 # Handle scripts, dependencies, and setuptools specific things
198 197 #---------------------------------------------------------------------------
199 198
200 199 # For some commands, use setuptools. Note that we do NOT list install here!
201 200 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
202 201 if len(set(('develop', 'sdist', 'release', 'bdist_egg', 'bdist_rpm',
203 202 'bdist', 'bdist_dumb', 'bdist_wininst', 'install_egg_info',
204 203 'build_sphinx', 'egg_info', 'easy_install', 'upload',
205 204 )).intersection(sys.argv)) > 0:
206 205 import setuptools
207 206
208 207 # This dict is used for passing extra arguments that are setuptools
209 208 # specific to setup
210 209 setuptools_extra_args = {}
211 210
212 211 if 'setuptools' in sys.modules:
213 212 setuptools_extra_args['zip_safe'] = False
214 setuptools_extra_args['entry_points'] = {
215 'console_scripts': find_scripts(True),
216 'gui_scripts': find_gui_scripts(True),
217 }
213 setuptools_extra_args['entry_points'] = find_scripts(True)
218 214 setup_args['extras_require'] = dict(
219 215 parallel = 'pyzmq>=2.1.4',
220 216 zmq = 'pyzmq>=2.0.10.1',
221 217 doc='Sphinx>=0.3',
222 218 test='nose>=0.10.1',
223 219 )
224 220 requires = setup_args.setdefault('install_requires', [])
225 221 setupext.display_status = False
226 222 if not setupext.check_for_readline():
227 223 if sys.platform == 'darwin':
228 224 requires.append('readline')
229 225 elif sys.platform.startswith('win'):
230 226 requires.append('pyreadline')
231 227 else:
232 228 pass
233 229 # do we want to install readline here?
234 230
235 231 # Script to be run by the windows binary installer after the default setup
236 232 # routine, to add shortcuts and similar windows-only things. Windows
237 233 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
238 234 # doesn't find them.
239 235 if 'bdist_wininst' in sys.argv:
240 236 if len(sys.argv) > 2 and \
241 237 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
242 238 print >> sys.stderr, "ERROR: bdist_wininst must be run alone. Exiting."
243 239 sys.exit(1)
244 240 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
245 241 else:
246 242 # If we are running without setuptools, call this function which will
247 243 # check for dependencies an inform the user what is needed. This is
248 244 # just to make life easy for users.
249 245 check_for_dependencies()
250 setup_args['scripts'] = find_scripts(False) + find_gui_scripts(False)
246 setup_args['scripts'] = find_scripts(False)
251 247
252 248 #---------------------------------------------------------------------------
253 249 # Do the actual setup now
254 250 #---------------------------------------------------------------------------
255 251
256 252 setup_args['cmdclass'] = {'build_py': record_commit_info('IPython')}
257 253 setup_args['packages'] = packages
258 254 setup_args['package_data'] = package_data
259 255 setup_args['data_files'] = data_files
260 256 setup_args.update(setuptools_extra_args)
261 257
262 258
263 259 if __name__ == '__main__':
264 260 setup(**setup_args)
265 261 cleanup()
@@ -1,404 +1,389
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 from ConfigParser import ConfigParser
27 27 from distutils.command.build_py import build_py
28 28 from glob import glob
29 29
30 30 from setupext import install_data_ext
31 31
32 32 #-------------------------------------------------------------------------------
33 33 # Useful globals and utility functions
34 34 #-------------------------------------------------------------------------------
35 35
36 36 # A few handy globals
37 37 isfile = os.path.isfile
38 38 pjoin = os.path.join
39 39
40 40 def oscmd(s):
41 41 print(">", s)
42 42 os.system(s)
43 43
44 44 # A little utility we'll need below, since glob() does NOT allow you to do
45 45 # exclusion on multiple endings!
46 46 def file_doesnt_endwith(test,endings):
47 47 """Return true if test is a file and its name does NOT end with any
48 48 of the strings listed in endings."""
49 49 if not isfile(test):
50 50 return False
51 51 for e in endings:
52 52 if test.endswith(e):
53 53 return False
54 54 return True
55 55
56 56 #---------------------------------------------------------------------------
57 57 # Basic project information
58 58 #---------------------------------------------------------------------------
59 59
60 60 # release.py contains version, authors, license, url, keywords, etc.
61 61 execfile(pjoin('IPython','core','release.py'))
62 62
63 63 # Create a dict with the basic information
64 64 # This dict is eventually passed to setup after additional keys are added.
65 65 setup_args = dict(
66 66 name = name,
67 67 version = version,
68 68 description = description,
69 69 long_description = long_description,
70 70 author = author,
71 71 author_email = author_email,
72 72 url = url,
73 73 download_url = download_url,
74 74 license = license,
75 75 platforms = platforms,
76 76 keywords = keywords,
77 77 cmdclass = {'install_data': install_data_ext},
78 78 )
79 79
80 80
81 81 #---------------------------------------------------------------------------
82 82 # Find packages
83 83 #---------------------------------------------------------------------------
84 84
85 85 def add_package(packages,pname,config=False,tests=False,scripts=False,
86 86 others=None):
87 87 """
88 88 Add a package to the list of packages, including certain subpackages.
89 89 """
90 90 packages.append('.'.join(['IPython',pname]))
91 91 if config:
92 92 packages.append('.'.join(['IPython',pname,'config']))
93 93 if tests:
94 94 packages.append('.'.join(['IPython',pname,'tests']))
95 95 if scripts:
96 96 packages.append('.'.join(['IPython',pname,'scripts']))
97 97 if others is not None:
98 98 for o in others:
99 99 packages.append('.'.join(['IPython',pname,o]))
100 100
101 101 def find_packages():
102 102 """
103 103 Find all of IPython's packages.
104 104 """
105 105 packages = ['IPython']
106 106 add_package(packages, 'config', tests=True, others=['default','profile'])
107 107 add_package(packages, 'core', tests=True)
108 108 add_package(packages, 'deathrow', tests=True)
109 109 add_package(packages, 'extensions')
110 110 add_package(packages, 'external')
111 111 add_package(packages, 'external.argparse')
112 112 add_package(packages, 'external.configobj')
113 113 add_package(packages, 'external.decorator')
114 114 add_package(packages, 'external.decorators')
115 115 add_package(packages, 'external.guid')
116 116 add_package(packages, 'external.Itpl')
117 117 add_package(packages, 'external.mglob')
118 118 add_package(packages, 'external.path')
119 119 add_package(packages, 'external.pexpect')
120 120 add_package(packages, 'external.pyparsing')
121 121 add_package(packages, 'external.simplegeneric')
122 122 add_package(packages, 'external.ssh')
123 123 add_package(packages, 'external.validate')
124 124 add_package(packages, 'kernel')
125 125 add_package(packages, 'frontend')
126 126 add_package(packages, 'frontend.qt')
127 127 add_package(packages, 'frontend.qt.console', tests=True)
128 128 add_package(packages, 'frontend.terminal', tests=True)
129 129 add_package(packages, 'lib', tests=True)
130 130 add_package(packages, 'parallel', tests=True, scripts=True,
131 131 others=['apps','engine','client','controller'])
132 132 add_package(packages, 'quarantine', tests=True)
133 133 add_package(packages, 'scripts')
134 134 add_package(packages, 'testing', tests=True)
135 135 add_package(packages, 'testing.plugin', tests=False)
136 136 add_package(packages, 'utils', tests=True)
137 137 add_package(packages, 'zmq')
138 138 add_package(packages, 'zmq.pylab')
139 139 add_package(packages, 'zmq.gui')
140 140 return packages
141 141
142 142 #---------------------------------------------------------------------------
143 143 # Find package data
144 144 #---------------------------------------------------------------------------
145 145
146 146 def find_package_data():
147 147 """
148 148 Find IPython's package_data.
149 149 """
150 150 # This is not enough for these things to appear in an sdist.
151 151 # We need to muck with the MANIFEST to get this to work
152 152 package_data = {
153 153 'IPython.config.userconfig' : ['*'],
154 154 'IPython.testing' : ['*.txt']
155 155 }
156 156 return package_data
157 157
158 158
159 159 #---------------------------------------------------------------------------
160 160 # Find data files
161 161 #---------------------------------------------------------------------------
162 162
163 163 def make_dir_struct(tag,base,out_base):
164 164 """Make the directory structure of all files below a starting dir.
165 165
166 166 This is just a convenience routine to help build a nested directory
167 167 hierarchy because distutils is too stupid to do this by itself.
168 168
169 169 XXX - this needs a proper docstring!
170 170 """
171 171
172 172 # we'll use these a lot below
173 173 lbase = len(base)
174 174 pathsep = os.path.sep
175 175 lpathsep = len(pathsep)
176 176
177 177 out = []
178 178 for (dirpath,dirnames,filenames) in os.walk(base):
179 179 # we need to strip out the dirpath from the base to map it to the
180 180 # output (installation) path. This requires possibly stripping the
181 181 # path separator, because otherwise pjoin will not work correctly
182 182 # (pjoin('foo/','/bar') returns '/bar').
183 183
184 184 dp_eff = dirpath[lbase:]
185 185 if dp_eff.startswith(pathsep):
186 186 dp_eff = dp_eff[lpathsep:]
187 187 # The output path must be anchored at the out_base marker
188 188 out_path = pjoin(out_base,dp_eff)
189 189 # Now we can generate the final filenames. Since os.walk only produces
190 190 # filenames, we must join back with the dirpath to get full valid file
191 191 # paths:
192 192 pfiles = [pjoin(dirpath,f) for f in filenames]
193 193 # Finally, generate the entry we need, which is a pari of (output
194 194 # path, files) for use as a data_files parameter in install_data.
195 195 out.append((out_path, pfiles))
196 196
197 197 return out
198 198
199 199
200 200 def find_data_files():
201 201 """
202 202 Find IPython's data_files.
203 203
204 204 Most of these are docs.
205 205 """
206 206
207 207 docdirbase = pjoin('share', 'doc', 'ipython')
208 208 manpagebase = pjoin('share', 'man', 'man1')
209 209
210 210 # Simple file lists can be made by hand
211 211 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
212 212 igridhelpfiles = filter(isfile,
213 213 glob(pjoin('IPython','extensions','igrid_help.*')))
214 214
215 215 # For nested structures, use the utility above
216 216 example_files = make_dir_struct(
217 217 'data',
218 218 pjoin('docs','examples'),
219 219 pjoin(docdirbase,'examples')
220 220 )
221 221 manual_files = make_dir_struct(
222 222 'data',
223 223 pjoin('docs','dist'),
224 224 pjoin(docdirbase,'manual')
225 225 )
226 226
227 227 # And assemble the entire output list
228 228 data_files = [ (manpagebase, manpages),
229 229 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
230 230 ] + manual_files + example_files
231 231
232 232 return data_files
233 233
234 234
235 235 def make_man_update_target(manpage):
236 236 """Return a target_update-compliant tuple for the given manpage.
237 237
238 238 Parameters
239 239 ----------
240 240 manpage : string
241 241 Name of the manpage, must include the section number (trailing number).
242 242
243 243 Example
244 244 -------
245 245
246 246 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
247 247 ('docs/man/ipython.1.gz',
248 248 ['docs/man/ipython.1'],
249 249 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
250 250 """
251 251 man_dir = pjoin('docs', 'man')
252 252 manpage_gz = manpage + '.gz'
253 253 manpath = pjoin(man_dir, manpage)
254 254 manpath_gz = pjoin(man_dir, manpage_gz)
255 255 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
256 256 locals() )
257 257 return (manpath_gz, [manpath], gz_cmd)
258 258
259 259 #---------------------------------------------------------------------------
260 260 # Find scripts
261 261 #---------------------------------------------------------------------------
262 262
263 263 def find_scripts(entry_points=False):
264 264 """Find IPython's scripts.
265 265
266 266 if entry_points is True:
267 267 return setuptools entry_point-style definitions
268 268 else:
269 269 return file paths of plain scripts [default]
270 270 """
271 271 if entry_points:
272 scripts = [
272 console_scripts = [
273 273 'ipython = IPython.frontend.terminal.ipapp:launch_new_instance',
274 274 'pycolor = IPython.utils.PyColorize:main',
275 275 'ipcontroller = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
276 276 'ipengine = IPython.parallel.apps.ipengineapp:launch_new_instance',
277 277 'iplogger = IPython.parallel.apps.iploggerapp:launch_new_instance',
278 278 'ipcluster = IPython.parallel.apps.ipclusterapp:launch_new_instance',
279 279 'iptest = IPython.testing.iptest:main',
280 280 'irunner = IPython.lib.irunner:main'
281 281 ]
282 gui_scripts = [
283 'ipython-qtconsole = IPython.frontend.qt.console.ipythonqt:main',
284 ]
285 scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
282 286 else:
283 287 parallel_scripts = pjoin('IPython','parallel','scripts')
284 288 main_scripts = pjoin('IPython','scripts')
285 289 scripts = [
286 290 pjoin(parallel_scripts, 'ipengine'),
287 291 pjoin(parallel_scripts, 'ipcontroller'),
288 292 pjoin(parallel_scripts, 'ipcluster'),
289 293 pjoin(parallel_scripts, 'iplogger'),
290 294 pjoin(main_scripts, 'ipython'),
295 pjoin(main_scripts, 'ipython-qtconsole'),
291 296 pjoin(main_scripts, 'pycolor'),
292 297 pjoin(main_scripts, 'irunner'),
293 298 pjoin(main_scripts, 'iptest')
294 299 ]
295 300 return scripts
296 301
297 def find_gui_scripts(entry_points=False):
298 """Find IPython's GUI scripts.
299
300 if entry_points is True:
301 return setuptools entry_point-style definitions
302 else:
303 return file paths of plain scripts [default]
304 """
305 if entry_points:
306 scripts = [
307 'ipython-qtconsole = IPython.frontend.qt.console.ipythonqt:main',
308 ]
309 else:
310 parallel_scripts = pjoin('IPython','parallel','scripts')
311 main_scripts = pjoin('IPython','scripts')
312 scripts = [
313 pjoin(main_scripts, 'ipython-qtconsole'),
314 ]
315 return scripts
316
317 302 #---------------------------------------------------------------------------
318 303 # Verify all dependencies
319 304 #---------------------------------------------------------------------------
320 305
321 306 def check_for_dependencies():
322 307 """Check for IPython's dependencies.
323 308
324 309 This function should NOT be called if running under setuptools!
325 310 """
326 311 from setupext.setupext import (
327 312 print_line, print_raw, print_status,
328 313 check_for_sphinx, check_for_pygments,
329 314 check_for_nose, check_for_pexpect,
330 315 check_for_pyzmq, check_for_readline
331 316 )
332 317 print_line()
333 318 print_raw("BUILDING IPYTHON")
334 319 print_status('python', sys.version)
335 320 print_status('platform', sys.platform)
336 321 if sys.platform == 'win32':
337 322 print_status('Windows version', sys.getwindowsversion())
338 323
339 324 print_raw("")
340 325 print_raw("OPTIONAL DEPENDENCIES")
341 326
342 327 check_for_sphinx()
343 328 check_for_pygments()
344 329 check_for_nose()
345 330 check_for_pexpect()
346 331 check_for_pyzmq()
347 332 check_for_readline()
348 333
349 334 def record_commit_info(pkg_dir, build_cmd=build_py):
350 335 """ Return extended build command class for recording commit
351 336
352 337 The extended command tries to run git to find the current commit, getting
353 338 the empty string if it fails. It then writes the commit hash into a file
354 339 in the `pkg_dir` path, named ``.git_commit_info.ini``.
355 340
356 341 In due course this information can be used by the package after it is
357 342 installed, to tell you what commit it was installed from if known.
358 343
359 344 To make use of this system, you need a package with a .git_commit_info.ini
360 345 file - e.g. ``myproject/.git_commit_info.ini`` - that might well look like
361 346 this::
362 347
363 348 # This is an ini file that may contain information about the code state
364 349 [commit hash]
365 350 # The line below may contain a valid hash if it has been substituted
366 351 # during 'git archive'
367 352 archive_subst_hash=$Format:%h$
368 353 # This line may be modified by the install process
369 354 install_hash=
370 355
371 356 The .git_commit_info file above is also designed to be used with git
372 357 substitution - so you probably also want a ``.gitattributes`` file in the
373 358 root directory of your working tree that contains something like this::
374 359
375 360 myproject/.git_commit_info.ini export-subst
376 361
377 362 That will cause the ``.git_commit_info.ini`` file to get filled in by ``git
378 363 archive`` - useful in case someone makes such an archive - for example with
379 364 via the github 'download source' button.
380 365
381 366 Although all the above will work as is, you might consider having something
382 367 like a ``get_info()`` function in your package to display the commit
383 368 information at the terminal. See the ``pkg_info.py`` module in the nipy
384 369 package for an example.
385 370 """
386 371 class MyBuildPy(build_cmd):
387 372 ''' Subclass to write commit data into installation tree '''
388 373 def run(self):
389 374 build_py.run(self)
390 375 import subprocess
391 376 proc = subprocess.Popen('git rev-parse --short HEAD',
392 377 stdout=subprocess.PIPE,
393 378 stderr=subprocess.PIPE,
394 379 shell=True)
395 380 repo_commit, _ = proc.communicate()
396 381 # We write the installation commit even if it's empty
397 382 cfg_parser = ConfigParser()
398 383 cfg_parser.read(pjoin(pkg_dir, '.git_commit_info.ini'))
399 384 cfg_parser.set('commit hash', 'install_hash', repo_commit)
400 385 out_pth = pjoin(self.build_lib, pkg_dir, '.git_commit_info.ini')
401 386 out_file = open(out_pth, 'wt')
402 387 cfg_parser.write(out_file)
403 388 out_file.close()
404 389 return MyBuildPy
General Comments 0
You need to be logged in to leave comments. Login now