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