##// END OF EJS Templates
Merge pull request #406 from jenshnielsen/zmqgui....
Evan Patterson -
r3814:4299a024 merge
parent child Browse files
Show More
@@ -1,387 +1,388 b''
1 1 # encoding: utf-8
2 2 """
3 3 This module defines the things that are used in setup.py for building IPython
4 4
5 5 This includes:
6 6
7 7 * The basic arguments to setup
8 8 * Functions for finding things like packages, package data, etc.
9 9 * A function for checking dependencies.
10 10 """
11 11 from __future__ import print_function
12 12
13 13 #-------------------------------------------------------------------------------
14 14 # Copyright (C) 2008 The IPython Development Team
15 15 #
16 16 # Distributed under the terms of the BSD License. The full license is in
17 17 # the file COPYING, distributed as part of this software.
18 18 #-------------------------------------------------------------------------------
19 19
20 20 #-------------------------------------------------------------------------------
21 21 # Imports
22 22 #-------------------------------------------------------------------------------
23 23 import os
24 24 import sys
25 25
26 26 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 add_package(packages, 'zmq.gui')
139 140 return packages
140 141
141 142 #---------------------------------------------------------------------------
142 143 # Find package data
143 144 #---------------------------------------------------------------------------
144 145
145 146 def find_package_data():
146 147 """
147 148 Find IPython's package_data.
148 149 """
149 150 # This is not enough for these things to appear in an sdist.
150 151 # We need to muck with the MANIFEST to get this to work
151 152 package_data = {
152 153 'IPython.config.userconfig' : ['*'],
153 154 'IPython.testing' : ['*.txt']
154 155 }
155 156 return package_data
156 157
157 158
158 159 #---------------------------------------------------------------------------
159 160 # Find data files
160 161 #---------------------------------------------------------------------------
161 162
162 163 def make_dir_struct(tag,base,out_base):
163 164 """Make the directory structure of all files below a starting dir.
164 165
165 166 This is just a convenience routine to help build a nested directory
166 167 hierarchy because distutils is too stupid to do this by itself.
167 168
168 169 XXX - this needs a proper docstring!
169 170 """
170 171
171 172 # we'll use these a lot below
172 173 lbase = len(base)
173 174 pathsep = os.path.sep
174 175 lpathsep = len(pathsep)
175 176
176 177 out = []
177 178 for (dirpath,dirnames,filenames) in os.walk(base):
178 179 # we need to strip out the dirpath from the base to map it to the
179 180 # output (installation) path. This requires possibly stripping the
180 181 # path separator, because otherwise pjoin will not work correctly
181 182 # (pjoin('foo/','/bar') returns '/bar').
182 183
183 184 dp_eff = dirpath[lbase:]
184 185 if dp_eff.startswith(pathsep):
185 186 dp_eff = dp_eff[lpathsep:]
186 187 # The output path must be anchored at the out_base marker
187 188 out_path = pjoin(out_base,dp_eff)
188 189 # Now we can generate the final filenames. Since os.walk only produces
189 190 # filenames, we must join back with the dirpath to get full valid file
190 191 # paths:
191 192 pfiles = [pjoin(dirpath,f) for f in filenames]
192 193 # Finally, generate the entry we need, which is a pari of (output
193 194 # path, files) for use as a data_files parameter in install_data.
194 195 out.append((out_path, pfiles))
195 196
196 197 return out
197 198
198 199
199 200 def find_data_files():
200 201 """
201 202 Find IPython's data_files.
202 203
203 204 Most of these are docs.
204 205 """
205 206
206 207 docdirbase = pjoin('share', 'doc', 'ipython')
207 208 manpagebase = pjoin('share', 'man', 'man1')
208 209
209 210 # Simple file lists can be made by hand
210 211 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
211 212 igridhelpfiles = filter(isfile,
212 213 glob(pjoin('IPython','extensions','igrid_help.*')))
213 214
214 215 # For nested structures, use the utility above
215 216 example_files = make_dir_struct(
216 217 'data',
217 218 pjoin('docs','examples'),
218 219 pjoin(docdirbase,'examples')
219 220 )
220 221 manual_files = make_dir_struct(
221 222 'data',
222 223 pjoin('docs','dist'),
223 224 pjoin(docdirbase,'manual')
224 225 )
225 226
226 227 # And assemble the entire output list
227 228 data_files = [ (manpagebase, manpages),
228 229 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
229 230 ] + manual_files + example_files
230 231
231 232 return data_files
232 233
233 234
234 235 def make_man_update_target(manpage):
235 236 """Return a target_update-compliant tuple for the given manpage.
236 237
237 238 Parameters
238 239 ----------
239 240 manpage : string
240 241 Name of the manpage, must include the section number (trailing number).
241 242
242 243 Example
243 244 -------
244 245
245 246 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
246 247 ('docs/man/ipython.1.gz',
247 248 ['docs/man/ipython.1'],
248 249 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
249 250 """
250 251 man_dir = pjoin('docs', 'man')
251 252 manpage_gz = manpage + '.gz'
252 253 manpath = pjoin(man_dir, manpage)
253 254 manpath_gz = pjoin(man_dir, manpage_gz)
254 255 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
255 256 locals() )
256 257 return (manpath_gz, [manpath], gz_cmd)
257 258
258 259 #---------------------------------------------------------------------------
259 260 # Find scripts
260 261 #---------------------------------------------------------------------------
261 262
262 263 def find_scripts(entry_points=False):
263 264 """Find IPython's scripts.
264 265
265 266 if entry_points is True:
266 267 return setuptools entry_point-style definitions
267 268 else:
268 269 return file paths of plain scripts [default]
269 270
270 271 """
271 272 if entry_points:
272 273 scripts = [
273 274 'ipython = IPython.frontend.terminal.ipapp:launch_new_instance',
274 275 'ipython-qtconsole = IPython.frontend.qt.console.ipythonqt:main',
275 276 'pycolor = IPython.utils.PyColorize:main',
276 277 'ipcontroller = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
277 278 'ipengine = IPython.parallel.apps.ipengineapp:launch_new_instance',
278 279 'iplogger = IPython.parallel.apps.iploggerapp:launch_new_instance',
279 280 'ipcluster = IPython.parallel.apps.ipclusterapp:launch_new_instance',
280 281 'iptest = IPython.testing.iptest:main',
281 282 'irunner = IPython.lib.irunner:main'
282 283 ]
283 284 else:
284 285 parallel_scripts = pjoin('IPython','parallel','scripts')
285 286 main_scripts = pjoin('IPython','scripts')
286 287 scripts = [
287 288 pjoin(parallel_scripts, 'ipengine'),
288 289 pjoin(parallel_scripts, 'ipcontroller'),
289 290 pjoin(parallel_scripts, 'ipcluster'),
290 291 pjoin(parallel_scripts, 'iplogger'),
291 292 pjoin(main_scripts, 'ipython'),
292 293 pjoin(main_scripts, 'ipython-qtconsole'),
293 294 pjoin(main_scripts, 'pycolor'),
294 295 pjoin(main_scripts, 'irunner'),
295 296 pjoin(main_scripts, 'iptest')
296 297 ]
297 298
298 299 return scripts
299 300
300 301 #---------------------------------------------------------------------------
301 302 # Verify all dependencies
302 303 #---------------------------------------------------------------------------
303 304
304 305 def check_for_dependencies():
305 306 """Check for IPython's dependencies.
306 307
307 308 This function should NOT be called if running under setuptools!
308 309 """
309 310 from setupext.setupext import (
310 311 print_line, print_raw, print_status,
311 312 check_for_sphinx, check_for_pygments,
312 313 check_for_nose, check_for_pexpect,
313 314 check_for_pyzmq, check_for_readline
314 315 )
315 316 print_line()
316 317 print_raw("BUILDING IPYTHON")
317 318 print_status('python', sys.version)
318 319 print_status('platform', sys.platform)
319 320 if sys.platform == 'win32':
320 321 print_status('Windows version', sys.getwindowsversion())
321 322
322 323 print_raw("")
323 324 print_raw("OPTIONAL DEPENDENCIES")
324 325
325 326 check_for_sphinx()
326 327 check_for_pygments()
327 328 check_for_nose()
328 329 check_for_pexpect()
329 330 check_for_pyzmq()
330 331 check_for_readline()
331 332
332 333 def record_commit_info(pkg_dir, build_cmd=build_py):
333 334 """ Return extended build command class for recording commit
334 335
335 336 The extended command tries to run git to find the current commit, getting
336 337 the empty string if it fails. It then writes the commit hash into a file
337 338 in the `pkg_dir` path, named ``.git_commit_info.ini``.
338 339
339 340 In due course this information can be used by the package after it is
340 341 installed, to tell you what commit it was installed from if known.
341 342
342 343 To make use of this system, you need a package with a .git_commit_info.ini
343 344 file - e.g. ``myproject/.git_commit_info.ini`` - that might well look like
344 345 this::
345 346
346 347 # This is an ini file that may contain information about the code state
347 348 [commit hash]
348 349 # The line below may contain a valid hash if it has been substituted
349 350 # during 'git archive'
350 351 archive_subst_hash=$Format:%h$
351 352 # This line may be modified by the install process
352 353 install_hash=
353 354
354 355 The .git_commit_info file above is also designed to be used with git
355 356 substitution - so you probably also want a ``.gitattributes`` file in the
356 357 root directory of your working tree that contains something like this::
357 358
358 359 myproject/.git_commit_info.ini export-subst
359 360
360 361 That will cause the ``.git_commit_info.ini`` file to get filled in by ``git
361 362 archive`` - useful in case someone makes such an archive - for example with
362 363 via the github 'download source' button.
363 364
364 365 Although all the above will work as is, you might consider having something
365 366 like a ``get_info()`` function in your package to display the commit
366 367 information at the terminal. See the ``pkg_info.py`` module in the nipy
367 368 package for an example.
368 369 """
369 370 class MyBuildPy(build_cmd):
370 371 ''' Subclass to write commit data into installation tree '''
371 372 def run(self):
372 373 build_py.run(self)
373 374 import subprocess
374 375 proc = subprocess.Popen('git rev-parse --short HEAD',
375 376 stdout=subprocess.PIPE,
376 377 stderr=subprocess.PIPE,
377 378 shell=True)
378 379 repo_commit, _ = proc.communicate()
379 380 # We write the installation commit even if it's empty
380 381 cfg_parser = ConfigParser()
381 382 cfg_parser.read(pjoin(pkg_dir, '.git_commit_info.ini'))
382 383 cfg_parser.set('commit hash', 'install_hash', repo_commit)
383 384 out_pth = pjoin(self.build_lib, pkg_dir, '.git_commit_info.ini')
384 385 out_file = open(out_pth, 'wt')
385 386 cfg_parser.write(out_file)
386 387 out_file.close()
387 388 return MyBuildPy
General Comments 0
You need to be logged in to leave comments. Login now