##// END OF EJS Templates
Merge pull request #5340 from minrk/btcss...
Paul Ivanov -
r15817:531268a9 merge
parent child Browse files
Show More
@@ -1,175 +1,176 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // Tour of IPython Notebok UI (with Bootstrap Tour)
10 10 //============================================================================
11 11
12 12 var tour_steps = [
13 13 {
14 14 element: $("#ipython_notebook"),
15 15 title: "Welcome to the Notebook Tour",
16 16 placement: 'bottom',
17 17 content: "This tour will take 2 minutes.",
18 18 backdrop: true,
19 19 }, {
20 20 element: "#notebook_name",
21 21 title: "Filename",
22 22 placement: 'bottom',
23 23 content: "Click here to change the filename for this notebook."
24 24 }, {
25 25 element: "#checkpoint_status",
26 26 title: "Checkpoint Status",
27 27 placement: 'bottom',
28 28 content: "Information about the last time this notebook was saved."
29 29 }, {
30 30 element: $("#menus").parent(),
31 31 placement: 'bottom',
32 32 backdrop: true,
33 33 title: "Notebook Menubar",
34 34 content: "The menubar has menus for actions on the notebook, its cells, and the kernel it communicates with."
35 35 }, {
36 36 element: "#maintoolbar",
37 37 placement: 'bottom',
38 38 backdrop: true,
39 39 title: "Notebook Toolbar",
40 40 content: "The toolbar has buttons for the most common actions. Hover your mouse over each button for more information."
41 41 }, {
42 42 element: "#modal_indicator",
43 43 title: "Mode Indicator",
44 44 placement: 'bottom',
45 45 content: "The Notebook has two modes: Edit Mode and Command Mode. In this area, an indicator can appear to tell you which mode you are in.",
46 46 onShow: function(tour) { command_icon_hack(); }
47 47 }, {
48 48 element: "#modal_indicator",
49 49 title: "Command Mode",
50 50 placement: 'bottom',
51 51 onShow: function(tour) { IPython.notebook.command_mode(); command_icon_hack(); },
52 52 onNext: function(tour) { edit_mode(); },
53 53 content: "Right now you are in Command Mode, and many keyboard shortcuts are available. In this mode, no icon is displayed in the indicator area."
54 54 }, {
55 55 element: "#modal_indicator",
56 56 title: "Edit Mode",
57 57 placement: 'bottom',
58 58 onShow: function(tour) { edit_mode(); },
59 59 content: "Pressing <code>enter</code> or clicking in the input text area of the cell switches to Edit Mode."
60 60 }, {
61 61 element: '.selected',
62 62 title: "Edit Mode",
63 63 placement: 'bottom',
64 64 onShow: function(tour) { edit_mode(); },
65 65 content: "Notice that the border around the currently active cell changed color. Typing will insert text into the currently active cell."
66 66 }, {
67 67 element: '.selected',
68 68 title: "Back to Command Mode",
69 69 placement: 'bottom',
70 70 onShow: function(tour) { IPython.notebook.command_mode(); },
71 71 content: "Pressing <code>esc</code> or clicking outside of the input text area takes you back to Command Mode."
72 72 }, {
73 73 element: '#keyboard_shortcuts',
74 74 title: "Keyboard Shortcuts",
75 75 placement: 'bottom',
76 76 onShow: function(tour) { $('#help_menu').parent().addClass('open'); },
77 77 onHide: function(tour) { $('#help_menu').parent().removeClass('open'); },
78 78 content: "You can click here to get a list of all of the keyboard shortcuts."
79 79 }, {
80 80 element: "#kernel_indicator",
81 81 title: "Kernel Indicator",
82 82 placement: 'bottom',
83 83 onShow: function(tour) { $([IPython.events]).trigger('status_idle.Kernel');},
84 84 content: "This is the Kernel indicator. It looks like this when the Kernel is idle.",
85 85 }, {
86 86 element: "#kernel_indicator",
87 87 title: "Kernel Indicator",
88 88 placement: 'bottom',
89 89 onShow: function(tour) { $([IPython.events]).trigger('status_busy.Kernel'); },
90 90 content: "The Kernel indicator looks like this when the Kernel is busy.",
91 91 }, {
92 92 element: ".icon-stop",
93 93 placement: 'bottom',
94 94 title: "Interrupting the Kernel",
95 95 onHide: function(tour) { $([IPython.events]).trigger('status_idle.Kernel'); },
96 96 content: "To cancel a computation in progress, you can click here."
97 97 }, {
98 98 element: "#notification_kernel",
99 99 placement: 'bottom',
100 100 onShow: function(tour) { $('.icon-stop').click(); },
101 101 title: "Notification Area",
102 102 content: "Messages in response to user actions (Save, Interrupt, etc) appear here."
103 103 }, {
104 104 element: "#ipython_notebook",
105 105 title: "Fin.",
106 106 placement: 'bottom',
107 107 backdrop: true,
108 108 content: "This concludes the IPython Notebook User Interface Tour. Happy hacking!",
109 109 }
110 110 ];
111 111
112 112 var tour_style = "<div class='popover tour' style='position:relative'>\
113 113 <div class='arrow'></div>\
114 114 <div style='position:absolute; top:7px; right:7px'>\
115 115 <button class='btn btn-sm icon-remove' data-role='end'></button></div>\
116 116 <h3 class='popover-title'></h3>\
117 117 <div class='popover-content'></div>\
118 118 <div class='popover-navigation'>\
119 119 <button class='btn btn-default icon-step-backward' data-role='prev'></button>\
120 120 <button class='btn btn-default icon-step-forward pull-right' data-role='next'></button>\
121 121 <button id='tour-pause' class='btn btn-sm btn-default icon-pause' data-resume-text='' data-pause-text='' data-role='pause-resume'></button>\
122 122 </div>\
123 123 </div>";
124 124
125 125 var command_icon_hack = function() {$('#modal_indicator').css('min-height', 20);}
126 126 var toggle_pause_play = function () { $('#tour-pause').toggleClass('icon-pause icon-play'); };
127 127 var edit_mode = function() {
128 128 IPython.notebook.focus_cell();
129 129 IPython.notebook.edit_mode();
130 130 ;}
131 131
132 132 IPython = (function (IPython) {
133 133 "use strict";
134 134
135 135
136 136 var NotebookTour = function () {
137 137 this.step_duration = 0;
138 138 this.tour_steps = tour_steps ;
139 139 this.tour_steps[0].content = "You can use the left and right arrow keys to go backwards and forwards.";
140 140 this.tour = new Tour({
141 141 //orphan: true,
142 142 storage: false, // start tour from beginning every time
143 143 //element: $("#ipython_notebook"),
144 144 debug: true,
145 145 reflex: true, // click on element to continue tour
146 146 //backdrop: true, // show dark behind popover
147 147 animation: false,
148 148 duration: this.step_duration,
149 149 onStart: function() { console.log('tour started'); },
150 150 // TODO: remove the onPause/onResume logic once pi's patch has been
151 151 // merged upstream to make this work via data-resume-class and
152 152 // data-resume-text attributes.
153 153 onPause: toggle_pause_play,
154 154 onResume: toggle_pause_play,
155 155 steps: this.tour_steps,
156 156 template: tour_style
157 157 });
158 this.tour.init();
158
159 159 };
160 160
161 161 NotebookTour.prototype.start = function () {
162 162 console.log("let's start the tour");
163 this.tour.init();
163 164 this.tour.start();
164 165 if (this.tour.ended())
165 166 {
166 167 this.tour.restart();
167 168 }
168 169 };
169 170
170 171 // Set module variables
171 172 IPython.NotebookTour = NotebookTour;
172 173
173 174 return IPython;
174 175
175 176 }(IPython));
@@ -1,698 +1,699 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 errno
24 24 import os
25 25 import sys
26 26
27 27 from distutils.command.build_py import build_py
28 28 from distutils.command.build_scripts import build_scripts
29 29 from distutils.command.install import install
30 30 from distutils.command.install_scripts import install_scripts
31 31 from distutils.cmd import Command
32 32 from glob import glob
33 33 from subprocess import call
34 34
35 35 from setupext import install_data_ext
36 36
37 37 #-------------------------------------------------------------------------------
38 38 # Useful globals and utility functions
39 39 #-------------------------------------------------------------------------------
40 40
41 41 # A few handy globals
42 42 isfile = os.path.isfile
43 43 pjoin = os.path.join
44 44 repo_root = os.path.dirname(os.path.abspath(__file__))
45 45
46 46 def oscmd(s):
47 47 print(">", s)
48 48 os.system(s)
49 49
50 50 # Py3 compatibility hacks, without assuming IPython itself is installed with
51 51 # the full py3compat machinery.
52 52
53 53 try:
54 54 execfile
55 55 except NameError:
56 56 def execfile(fname, globs, locs=None):
57 57 locs = locs or globs
58 58 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
59 59
60 60 # A little utility we'll need below, since glob() does NOT allow you to do
61 61 # exclusion on multiple endings!
62 62 def file_doesnt_endwith(test,endings):
63 63 """Return true if test is a file and its name does NOT end with any
64 64 of the strings listed in endings."""
65 65 if not isfile(test):
66 66 return False
67 67 for e in endings:
68 68 if test.endswith(e):
69 69 return False
70 70 return True
71 71
72 72 #---------------------------------------------------------------------------
73 73 # Basic project information
74 74 #---------------------------------------------------------------------------
75 75
76 76 # release.py contains version, authors, license, url, keywords, etc.
77 77 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
78 78
79 79 # Create a dict with the basic information
80 80 # This dict is eventually passed to setup after additional keys are added.
81 81 setup_args = dict(
82 82 name = name,
83 83 version = version,
84 84 description = description,
85 85 long_description = long_description,
86 86 author = author,
87 87 author_email = author_email,
88 88 url = url,
89 89 download_url = download_url,
90 90 license = license,
91 91 platforms = platforms,
92 92 keywords = keywords,
93 93 classifiers = classifiers,
94 94 cmdclass = {'install_data': install_data_ext},
95 95 )
96 96
97 97
98 98 #---------------------------------------------------------------------------
99 99 # Find packages
100 100 #---------------------------------------------------------------------------
101 101
102 102 def find_packages():
103 103 """
104 104 Find all of IPython's packages.
105 105 """
106 106 excludes = ['deathrow', 'quarantine']
107 107 packages = []
108 108 for dir,subdirs,files in os.walk('IPython'):
109 109 package = dir.replace(os.path.sep, '.')
110 110 if any(package.startswith('IPython.'+exc) for exc in excludes):
111 111 # package is to be excluded (e.g. deathrow)
112 112 continue
113 113 if '__init__.py' not in files:
114 114 # not a package
115 115 continue
116 116 packages.append(package)
117 117 return packages
118 118
119 119 #---------------------------------------------------------------------------
120 120 # Find package data
121 121 #---------------------------------------------------------------------------
122 122
123 123 def find_package_data():
124 124 """
125 125 Find IPython's package_data.
126 126 """
127 127 # This is not enough for these things to appear in an sdist.
128 128 # We need to muck with the MANIFEST to get this to work
129 129
130 130 # exclude components from the walk,
131 131 # we will build the components separately
132 132 excludes = ['components']
133 133
134 134 # add 'static/' prefix to exclusions, and tuplify for use in startswith
135 135 excludes = tuple([pjoin('static', ex) for ex in excludes])
136 136
137 137 # walk notebook resources:
138 138 cwd = os.getcwd()
139 139 os.chdir(os.path.join('IPython', 'html'))
140 140 static_data = []
141 141 for parent, dirs, files in os.walk('static'):
142 142 if parent.startswith(excludes):
143 143 continue
144 144 for f in files:
145 145 static_data.append(pjoin(parent, f))
146 146 components = pjoin("static", "components")
147 147 # select the components we actually need to install
148 148 # (there are lots of resources we bundle for sdist-reasons that we don't actually use)
149 149 static_data.extend([
150 150 pjoin(components, "backbone", "backbone-min.js"),
151 151 pjoin(components, "bootstrap", "bootstrap", "js", "bootstrap.min.js"),
152 pjoin(components, "bootstrap-tour", "build", "css", "bootstrap-tour.min.css"),
152 153 pjoin(components, "bootstrap-tour", "build", "js", "bootstrap-tour.min.js"),
153 154 pjoin(components, "font-awesome", "font", "*.*"),
154 155 pjoin(components, "google-caja", "html-css-sanitizer-minified.js"),
155 156 pjoin(components, "highlight.js", "build", "highlight.pack.js"),
156 157 pjoin(components, "jquery", "jquery.min.js"),
157 158 pjoin(components, "jquery-ui", "ui", "minified", "jquery-ui.min.js"),
158 159 pjoin(components, "jquery-ui", "themes", "smoothness", "jquery-ui.min.css"),
159 160 pjoin(components, "marked", "lib", "marked.js"),
160 161 pjoin(components, "requirejs", "require.js"),
161 162 pjoin(components, "underscore", "underscore-min.js"),
162 163 ])
163 164
164 165 # Ship all of Codemirror's CSS and JS
165 166 for parent, dirs, files in os.walk(pjoin(components, 'codemirror')):
166 167 for f in files:
167 168 if f.endswith(('.js', '.css')):
168 169 static_data.append(pjoin(parent, f))
169 170
170 171 os.chdir(os.path.join('tests',))
171 172 js_tests = glob('*.js') + glob('*/*.js')
172 173
173 174 os.chdir(os.path.join(cwd, 'IPython', 'nbconvert'))
174 175 nbconvert_templates = [os.path.join(dirpath, '*.*')
175 176 for dirpath, _, _ in os.walk('templates')]
176 177
177 178 os.chdir(cwd)
178 179
179 180 package_data = {
180 181 'IPython.config.profile' : ['README*', '*/*.py'],
181 182 'IPython.core.tests' : ['*.png', '*.jpg'],
182 183 'IPython.lib.tests' : ['*.wav'],
183 184 'IPython.testing.plugin' : ['*.txt'],
184 185 'IPython.html' : ['templates/*'] + static_data,
185 186 'IPython.html.tests' : js_tests,
186 187 'IPython.qt.console' : ['resources/icon/*.svg'],
187 188 'IPython.nbconvert' : nbconvert_templates +
188 189 ['tests/files/*.*', 'exporters/tests/files/*.*'],
189 190 'IPython.nbconvert.filters' : ['marked.js'],
190 191 'IPython.nbformat' : ['tests/*.ipynb']
191 192 }
192 193
193 194 return package_data
194 195
195 196
196 197 def check_package_data(package_data):
197 198 """verify that package_data globs make sense"""
198 199 print("checking package data")
199 200 for pkg, data in package_data.items():
200 201 pkg_root = pjoin(*pkg.split('.'))
201 202 for d in data:
202 203 path = pjoin(pkg_root, d)
203 204 if '*' in path:
204 205 assert len(glob(path)) > 0, "No files match pattern %s" % path
205 206 else:
206 207 assert os.path.exists(path), "Missing package data: %s" % path
207 208
208 209
209 210 def check_package_data_first(command):
210 211 """decorator for checking package_data before running a given command
211 212
212 213 Probably only needs to wrap build_py
213 214 """
214 215 class DecoratedCommand(command):
215 216 def run(self):
216 217 check_package_data(self.package_data)
217 218 command.run(self)
218 219 return DecoratedCommand
219 220
220 221
221 222 #---------------------------------------------------------------------------
222 223 # Find data files
223 224 #---------------------------------------------------------------------------
224 225
225 226 def make_dir_struct(tag,base,out_base):
226 227 """Make the directory structure of all files below a starting dir.
227 228
228 229 This is just a convenience routine to help build a nested directory
229 230 hierarchy because distutils is too stupid to do this by itself.
230 231
231 232 XXX - this needs a proper docstring!
232 233 """
233 234
234 235 # we'll use these a lot below
235 236 lbase = len(base)
236 237 pathsep = os.path.sep
237 238 lpathsep = len(pathsep)
238 239
239 240 out = []
240 241 for (dirpath,dirnames,filenames) in os.walk(base):
241 242 # we need to strip out the dirpath from the base to map it to the
242 243 # output (installation) path. This requires possibly stripping the
243 244 # path separator, because otherwise pjoin will not work correctly
244 245 # (pjoin('foo/','/bar') returns '/bar').
245 246
246 247 dp_eff = dirpath[lbase:]
247 248 if dp_eff.startswith(pathsep):
248 249 dp_eff = dp_eff[lpathsep:]
249 250 # The output path must be anchored at the out_base marker
250 251 out_path = pjoin(out_base,dp_eff)
251 252 # Now we can generate the final filenames. Since os.walk only produces
252 253 # filenames, we must join back with the dirpath to get full valid file
253 254 # paths:
254 255 pfiles = [pjoin(dirpath,f) for f in filenames]
255 256 # Finally, generate the entry we need, which is a pari of (output
256 257 # path, files) for use as a data_files parameter in install_data.
257 258 out.append((out_path, pfiles))
258 259
259 260 return out
260 261
261 262
262 263 def find_data_files():
263 264 """
264 265 Find IPython's data_files.
265 266
266 267 Just man pages at this point.
267 268 """
268 269
269 270 manpagebase = pjoin('share', 'man', 'man1')
270 271
271 272 # Simple file lists can be made by hand
272 273 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
273 274 if not manpages:
274 275 # When running from a source tree, the manpages aren't gzipped
275 276 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
276 277
277 278 # And assemble the entire output list
278 279 data_files = [ (manpagebase, manpages) ]
279 280
280 281 return data_files
281 282
282 283
283 284 def make_man_update_target(manpage):
284 285 """Return a target_update-compliant tuple for the given manpage.
285 286
286 287 Parameters
287 288 ----------
288 289 manpage : string
289 290 Name of the manpage, must include the section number (trailing number).
290 291
291 292 Example
292 293 -------
293 294
294 295 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
295 296 ('docs/man/ipython.1.gz',
296 297 ['docs/man/ipython.1'],
297 298 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
298 299 """
299 300 man_dir = pjoin('docs', 'man')
300 301 manpage_gz = manpage + '.gz'
301 302 manpath = pjoin(man_dir, manpage)
302 303 manpath_gz = pjoin(man_dir, manpage_gz)
303 304 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
304 305 locals() )
305 306 return (manpath_gz, [manpath], gz_cmd)
306 307
307 308 # The two functions below are copied from IPython.utils.path, so we don't need
308 309 # to import IPython during setup, which fails on Python 3.
309 310
310 311 def target_outdated(target,deps):
311 312 """Determine whether a target is out of date.
312 313
313 314 target_outdated(target,deps) -> 1/0
314 315
315 316 deps: list of filenames which MUST exist.
316 317 target: single filename which may or may not exist.
317 318
318 319 If target doesn't exist or is older than any file listed in deps, return
319 320 true, otherwise return false.
320 321 """
321 322 try:
322 323 target_time = os.path.getmtime(target)
323 324 except os.error:
324 325 return 1
325 326 for dep in deps:
326 327 dep_time = os.path.getmtime(dep)
327 328 if dep_time > target_time:
328 329 #print "For target",target,"Dep failed:",dep # dbg
329 330 #print "times (dep,tar):",dep_time,target_time # dbg
330 331 return 1
331 332 return 0
332 333
333 334
334 335 def target_update(target,deps,cmd):
335 336 """Update a target with a given command given a list of dependencies.
336 337
337 338 target_update(target,deps,cmd) -> runs cmd if target is outdated.
338 339
339 340 This is just a wrapper around target_outdated() which calls the given
340 341 command if target is outdated."""
341 342
342 343 if target_outdated(target,deps):
343 344 os.system(cmd)
344 345
345 346 #---------------------------------------------------------------------------
346 347 # Find scripts
347 348 #---------------------------------------------------------------------------
348 349
349 350 def find_entry_points():
350 351 """Find IPython's scripts.
351 352
352 353 if entry_points is True:
353 354 return setuptools entry_point-style definitions
354 355 else:
355 356 return file paths of plain scripts [default]
356 357
357 358 suffix is appended to script names if entry_points is True, so that the
358 359 Python 3 scripts get named "ipython3" etc.
359 360 """
360 361 ep = [
361 362 'ipython%s = IPython:start_ipython',
362 363 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
363 364 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
364 365 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
365 366 'iptest%s = IPython.testing.iptestcontroller:main',
366 367 ]
367 368 suffix = str(sys.version_info[0])
368 369 return [e % '' for e in ep] + [e % suffix for e in ep]
369 370
370 371 script_src = """#!{executable}
371 372 # This script was automatically generated by setup.py
372 373 if __name__ == '__main__':
373 374 from {mod} import {func}
374 375 {func}()
375 376 """
376 377
377 378 class build_scripts_entrypt(build_scripts):
378 379 def run(self):
379 380 self.mkpath(self.build_dir)
380 381 outfiles = []
381 382 for script in find_entry_points():
382 383 name, entrypt = script.split('=')
383 384 name = name.strip()
384 385 entrypt = entrypt.strip()
385 386 outfile = os.path.join(self.build_dir, name)
386 387 outfiles.append(outfile)
387 388 print('Writing script to', outfile)
388 389
389 390 mod, func = entrypt.split(':')
390 391 with open(outfile, 'w') as f:
391 392 f.write(script_src.format(executable=sys.executable,
392 393 mod=mod, func=func))
393 394
394 395 return outfiles, outfiles
395 396
396 397 class install_lib_symlink(Command):
397 398 user_options = [
398 399 ('install-dir=', 'd', "directory to install to"),
399 400 ]
400 401
401 402 def initialize_options(self):
402 403 self.install_dir = None
403 404
404 405 def finalize_options(self):
405 406 self.set_undefined_options('symlink',
406 407 ('install_lib', 'install_dir'),
407 408 )
408 409
409 410 def run(self):
410 411 if sys.platform == 'win32':
411 412 raise Exception("This doesn't work on Windows.")
412 413 pkg = os.path.join(os.getcwd(), 'IPython')
413 414 dest = os.path.join(self.install_dir, 'IPython')
414 415 if os.path.islink(dest):
415 416 print('removing existing symlink at %s' % dest)
416 417 os.unlink(dest)
417 418 print('symlinking %s -> %s' % (pkg, dest))
418 419 os.symlink(pkg, dest)
419 420
420 421 class unsymlink(install):
421 422 def run(self):
422 423 dest = os.path.join(self.install_lib, 'IPython')
423 424 if os.path.islink(dest):
424 425 print('removing symlink at %s' % dest)
425 426 os.unlink(dest)
426 427 else:
427 428 print('No symlink exists at %s' % dest)
428 429
429 430 class install_symlinked(install):
430 431 def run(self):
431 432 if sys.platform == 'win32':
432 433 raise Exception("This doesn't work on Windows.")
433 434
434 435 # Run all sub-commands (at least those that need to be run)
435 436 for cmd_name in self.get_sub_commands():
436 437 self.run_command(cmd_name)
437 438
438 439 # 'sub_commands': a list of commands this command might have to run to
439 440 # get its work done. See cmd.py for more info.
440 441 sub_commands = [('install_lib_symlink', lambda self:True),
441 442 ('install_scripts_sym', lambda self:True),
442 443 ]
443 444
444 445 class install_scripts_for_symlink(install_scripts):
445 446 """Redefined to get options from 'symlink' instead of 'install'.
446 447
447 448 I love distutils almost as much as I love setuptools.
448 449 """
449 450 def finalize_options(self):
450 451 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
451 452 self.set_undefined_options('symlink',
452 453 ('install_scripts', 'install_dir'),
453 454 ('force', 'force'),
454 455 ('skip_build', 'skip_build'),
455 456 )
456 457
457 458 #---------------------------------------------------------------------------
458 459 # Verify all dependencies
459 460 #---------------------------------------------------------------------------
460 461
461 462 def check_for_dependencies():
462 463 """Check for IPython's dependencies.
463 464
464 465 This function should NOT be called if running under setuptools!
465 466 """
466 467 from setupext.setupext import (
467 468 print_line, print_raw, print_status,
468 469 check_for_sphinx, check_for_pygments,
469 470 check_for_nose, check_for_pexpect,
470 471 check_for_pyzmq, check_for_readline,
471 472 check_for_jinja2, check_for_tornado
472 473 )
473 474 print_line()
474 475 print_raw("BUILDING IPYTHON")
475 476 print_status('python', sys.version)
476 477 print_status('platform', sys.platform)
477 478 if sys.platform == 'win32':
478 479 print_status('Windows version', sys.getwindowsversion())
479 480
480 481 print_raw("")
481 482 print_raw("OPTIONAL DEPENDENCIES")
482 483
483 484 check_for_sphinx()
484 485 check_for_pygments()
485 486 check_for_nose()
486 487 if os.name == 'posix':
487 488 check_for_pexpect()
488 489 check_for_pyzmq()
489 490 check_for_tornado()
490 491 check_for_readline()
491 492 check_for_jinja2()
492 493
493 494 #---------------------------------------------------------------------------
494 495 # VCS related
495 496 #---------------------------------------------------------------------------
496 497
497 498 # utils.submodule has checks for submodule status
498 499 execfile(pjoin('IPython','utils','submodule.py'), globals())
499 500
500 501 class UpdateSubmodules(Command):
501 502 """Update git submodules
502 503
503 504 IPython's external javascript dependencies live in a separate repo.
504 505 """
505 506 description = "Update git submodules"
506 507 user_options = []
507 508
508 509 def initialize_options(self):
509 510 pass
510 511
511 512 def finalize_options(self):
512 513 pass
513 514
514 515 def run(self):
515 516 failure = False
516 517 try:
517 518 self.spawn('git submodule init'.split())
518 519 self.spawn('git submodule update --recursive'.split())
519 520 except Exception as e:
520 521 failure = e
521 522 print(e)
522 523
523 524 if not check_submodule_status(repo_root) == 'clean':
524 525 print("submodules could not be checked out")
525 526 sys.exit(1)
526 527
527 528
528 529 def git_prebuild(pkg_dir, build_cmd=build_py):
529 530 """Return extended build or sdist command class for recording commit
530 531
531 532 records git commit in IPython.utils._sysinfo.commit
532 533
533 534 for use in IPython.utils.sysinfo.sys_info() calls after installation.
534 535
535 536 Also ensures that submodules exist prior to running
536 537 """
537 538
538 539 class MyBuildPy(build_cmd):
539 540 ''' Subclass to write commit data into installation tree '''
540 541 def run(self):
541 542 build_cmd.run(self)
542 543 # this one will only fire for build commands
543 544 if hasattr(self, 'build_lib'):
544 545 self._record_commit(self.build_lib)
545 546
546 547 def make_release_tree(self, base_dir, files):
547 548 # this one will fire for sdist
548 549 build_cmd.make_release_tree(self, base_dir, files)
549 550 self._record_commit(base_dir)
550 551
551 552 def _record_commit(self, base_dir):
552 553 import subprocess
553 554 proc = subprocess.Popen('git rev-parse --short HEAD',
554 555 stdout=subprocess.PIPE,
555 556 stderr=subprocess.PIPE,
556 557 shell=True)
557 558 repo_commit, _ = proc.communicate()
558 559 repo_commit = repo_commit.strip().decode("ascii")
559 560
560 561 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
561 562 if os.path.isfile(out_pth) and not repo_commit:
562 563 # nothing to write, don't clobber
563 564 return
564 565
565 566 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
566 567
567 568 # remove to avoid overwriting original via hard link
568 569 try:
569 570 os.remove(out_pth)
570 571 except (IOError, OSError):
571 572 pass
572 573 with open(out_pth, 'w') as out_file:
573 574 out_file.writelines([
574 575 '# GENERATED BY setup.py\n',
575 576 'commit = "%s"\n' % repo_commit,
576 577 ])
577 578 return require_submodules(MyBuildPy)
578 579
579 580
580 581 def require_submodules(command):
581 582 """decorator for instructing a command to check for submodules before running"""
582 583 class DecoratedCommand(command):
583 584 def run(self):
584 585 if not check_submodule_status(repo_root) == 'clean':
585 586 print("submodules missing! Run `setup.py submodule` and try again")
586 587 sys.exit(1)
587 588 command.run(self)
588 589 return DecoratedCommand
589 590
590 591 #---------------------------------------------------------------------------
591 592 # bdist related
592 593 #---------------------------------------------------------------------------
593 594
594 595 def get_bdist_wheel():
595 596 """Construct bdist_wheel command for building wheels
596 597
597 598 Constructs py2-none-any tag, instead of py2.7-none-any
598 599 """
599 600 class RequiresWheel(Command):
600 601 description = "Dummy command for missing bdist_wheel"
601 602 user_options = []
602 603
603 604 def initialize_options(self):
604 605 pass
605 606
606 607 def finalize_options(self):
607 608 pass
608 609
609 610 def run(self):
610 611 print("bdist_wheel requires the wheel package")
611 612 sys.exit(1)
612 613
613 614 if 'setuptools' not in sys.modules:
614 615 return RequiresWheel
615 616 else:
616 617 try:
617 618 from wheel.bdist_wheel import bdist_wheel, read_pkg_info, write_pkg_info
618 619 except ImportError:
619 620 return RequiresWheel
620 621
621 622 class bdist_wheel_tag(bdist_wheel):
622 623
623 624 def get_tag(self):
624 625 return ('py%i' % sys.version_info[0], 'none', 'any')
625 626
626 627 def add_requirements(self, metadata_path):
627 628 """transform platform-dependent requirements"""
628 629 pkg_info = read_pkg_info(metadata_path)
629 630 # pkg_info is an email.Message object (?!)
630 631 # we have to remove the unconditional 'readline' and/or 'pyreadline' entries
631 632 # and transform them to conditionals
632 633 requires = pkg_info.get_all('Requires-Dist')
633 634 del pkg_info['Requires-Dist']
634 635 def _remove_startswith(lis, prefix):
635 636 """like list.remove, but with startswith instead of =="""
636 637 found = False
637 638 for idx, item in enumerate(lis):
638 639 if item.startswith(prefix):
639 640 found = True
640 641 break
641 642 if found:
642 643 lis.pop(idx)
643 644
644 645 for pkg in ("gnureadline", "pyreadline", "mock"):
645 646 _remove_startswith(requires, pkg)
646 647 requires.append("gnureadline; sys.platform == 'darwin' and platform.python_implementation == 'CPython'")
647 648 requires.append("pyreadline (>=2.0); sys.platform == 'win32' and platform.python_implementation == 'CPython'")
648 649 requires.append("mock; extra == 'test' and python_version < '3.3'")
649 650 for r in requires:
650 651 pkg_info['Requires-Dist'] = r
651 652 write_pkg_info(metadata_path, pkg_info)
652 653
653 654 return bdist_wheel_tag
654 655
655 656 #---------------------------------------------------------------------------
656 657 # Notebook related
657 658 #---------------------------------------------------------------------------
658 659
659 660 class CompileCSS(Command):
660 661 """Recompile Notebook CSS
661 662
662 663 Regenerate the compiled CSS from LESS sources.
663 664
664 665 Requires various dev dependencies, such as fabric and lessc.
665 666 """
666 667 description = "Recompile Notebook CSS"
667 668 user_options = []
668 669
669 670 def initialize_options(self):
670 671 pass
671 672
672 673 def finalize_options(self):
673 674 pass
674 675
675 676 def run(self):
676 677 call("fab css", shell=True, cwd=pjoin(repo_root, "IPython", "html"))
677 678
678 679 class JavascriptVersion(Command):
679 680 """write the javascript version to notebook javascript"""
680 681 description = "Write IPython version to javascript"
681 682 user_options = []
682 683
683 684 def initialize_options(self):
684 685 pass
685 686
686 687 def finalize_options(self):
687 688 pass
688 689
689 690 def run(self):
690 691 nsfile = pjoin(repo_root, "IPython", "html", "static", "base", "js", "namespace.js")
691 692 with open(nsfile) as f:
692 693 lines = f.readlines()
693 694 with open(nsfile, 'w') as f:
694 695 for line in lines:
695 696 if line.startswith("IPython.version"):
696 697 line = 'IPython.version = "{0}";\n'.format(version)
697 698 f.write(line)
698 699
General Comments 0
You need to be logged in to leave comments. Login now