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