##// END OF EJS Templates
Added test in ipcluster.py to see if the platform is win32. If so,...
Brian Granger -
Show More
@@ -1,342 +1,347 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3
3
4 """Start an IPython cluster conveniently, either locally or remotely.
4 """Start an IPython cluster conveniently, either locally or remotely.
5
5
6 Basic usage
6 Basic usage
7 -----------
7 -----------
8
8
9 For local operation, the simplest mode of usage is:
9 For local operation, the simplest mode of usage is:
10
10
11 %prog -n N
11 %prog -n N
12
12
13 where N is the number of engines you want started.
13 where N is the number of engines you want started.
14
14
15 For remote operation, you must call it with a cluster description file:
15 For remote operation, you must call it with a cluster description file:
16
16
17 %prog -f clusterfile.py
17 %prog -f clusterfile.py
18
18
19 The cluster file is a normal Python script which gets run via execfile(). You
19 The cluster file is a normal Python script which gets run via execfile(). You
20 can have arbitrary logic in it, but all that matters is that at the end of the
20 can have arbitrary logic in it, but all that matters is that at the end of the
21 execution, it declares the variables 'controller', 'engines', and optionally
21 execution, it declares the variables 'controller', 'engines', and optionally
22 'sshx'. See the accompanying examples for details on what these variables must
22 'sshx'. See the accompanying examples for details on what these variables must
23 contain.
23 contain.
24
24
25
25
26 Notes
26 Notes
27 -----
27 -----
28
28
29 WARNING: this code is still UNFINISHED and EXPERIMENTAL! It is incomplete,
29 WARNING: this code is still UNFINISHED and EXPERIMENTAL! It is incomplete,
30 some listed options are not really implemented, and all of its interfaces are
30 some listed options are not really implemented, and all of its interfaces are
31 subject to change.
31 subject to change.
32
32
33 When operating over SSH for a remote cluster, this program relies on the
33 When operating over SSH for a remote cluster, this program relies on the
34 existence of a particular script called 'sshx'. This script must live in the
34 existence of a particular script called 'sshx'. This script must live in the
35 target systems where you'll be running your controller and engines, and is
35 target systems where you'll be running your controller and engines, and is
36 needed to configure your PATH and PYTHONPATH variables for further execution of
36 needed to configure your PATH and PYTHONPATH variables for further execution of
37 python code at the other end of an SSH connection. The script can be as simple
37 python code at the other end of an SSH connection. The script can be as simple
38 as:
38 as:
39
39
40 #!/bin/sh
40 #!/bin/sh
41 . $HOME/.bashrc
41 . $HOME/.bashrc
42 "$@"
42 "$@"
43
43
44 which is the default one provided by IPython. You can modify this or provide
44 which is the default one provided by IPython. You can modify this or provide
45 your own. Since it's quite likely that for different clusters you may need
45 your own. Since it's quite likely that for different clusters you may need
46 this script to configure things differently or that it may live in different
46 this script to configure things differently or that it may live in different
47 locations, its full path can be set in the same file where you define the
47 locations, its full path can be set in the same file where you define the
48 cluster setup. IPython's order of evaluation for this variable is the
48 cluster setup. IPython's order of evaluation for this variable is the
49 following:
49 following:
50
50
51 a) Internal default: 'sshx'. This only works if it is in the default system
51 a) Internal default: 'sshx'. This only works if it is in the default system
52 path which SSH sets up in non-interactive mode.
52 path which SSH sets up in non-interactive mode.
53
53
54 b) Environment variable: if $IPYTHON_SSHX is defined, this overrides the
54 b) Environment variable: if $IPYTHON_SSHX is defined, this overrides the
55 internal default.
55 internal default.
56
56
57 c) Variable 'sshx' in the cluster configuration file: finally, this will
57 c) Variable 'sshx' in the cluster configuration file: finally, this will
58 override the previous two values.
58 override the previous two values.
59
59
60 This code is Unix-only, with precious little hope of any of this ever working
60 This code is Unix-only, with precious little hope of any of this ever working
61 under Windows, since we need SSH from the ground up, we background processes,
61 under Windows, since we need SSH from the ground up, we background processes,
62 etc. Ports of this functionality to Windows are welcome.
62 etc. Ports of this functionality to Windows are welcome.
63
63
64
64
65 Call summary
65 Call summary
66 ------------
66 ------------
67
67
68 %prog [options]
68 %prog [options]
69 """
69 """
70
70
71 __docformat__ = "restructuredtext en"
71 __docformat__ = "restructuredtext en"
72
72
73 #-------------------------------------------------------------------------------
73 #-------------------------------------------------------------------------------
74 # Copyright (C) 2008 The IPython Development Team
74 # Copyright (C) 2008 The IPython Development Team
75 #
75 #
76 # Distributed under the terms of the BSD License. The full license is in
76 # Distributed under the terms of the BSD License. The full license is in
77 # the file COPYING, distributed as part of this software.
77 # the file COPYING, distributed as part of this software.
78 #-------------------------------------------------------------------------------
78 #-------------------------------------------------------------------------------
79
79
80 #-------------------------------------------------------------------------------
80 #-------------------------------------------------------------------------------
81 # Stdlib imports
81 # Stdlib imports
82 #-------------------------------------------------------------------------------
82 #-------------------------------------------------------------------------------
83
83
84 import os
84 import os
85 import signal
85 import signal
86 import sys
86 import sys
87 import time
87 import time
88
88
89 from optparse import OptionParser
89 from optparse import OptionParser
90 from subprocess import Popen,call
90 from subprocess import Popen,call
91
91
92 #---------------------------------------------------------------------------
92 #---------------------------------------------------------------------------
93 # IPython imports
93 # IPython imports
94 #---------------------------------------------------------------------------
94 #---------------------------------------------------------------------------
95 from IPython.tools import utils
95 from IPython.tools import utils
96 from IPython.genutils import get_ipython_dir
96 from IPython.genutils import get_ipython_dir
97
97
98 #---------------------------------------------------------------------------
98 #---------------------------------------------------------------------------
99 # Normal code begins
99 # Normal code begins
100 #---------------------------------------------------------------------------
100 #---------------------------------------------------------------------------
101
101
102 def parse_args():
102 def parse_args():
103 """Parse command line and return opts,args."""
103 """Parse command line and return opts,args."""
104
104
105 parser = OptionParser(usage=__doc__)
105 parser = OptionParser(usage=__doc__)
106 newopt = parser.add_option # shorthand
106 newopt = parser.add_option # shorthand
107
107
108 newopt("--controller-port", type="int", dest="controllerport",
108 newopt("--controller-port", type="int", dest="controllerport",
109 help="the TCP port the controller is listening on")
109 help="the TCP port the controller is listening on")
110
110
111 newopt("--controller-ip", type="string", dest="controllerip",
111 newopt("--controller-ip", type="string", dest="controllerip",
112 help="the TCP ip address of the controller")
112 help="the TCP ip address of the controller")
113
113
114 newopt("-n", "--num", type="int", dest="n",default=2,
114 newopt("-n", "--num", type="int", dest="n",default=2,
115 help="the number of engines to start")
115 help="the number of engines to start")
116
116
117 newopt("--engine-port", type="int", dest="engineport",
117 newopt("--engine-port", type="int", dest="engineport",
118 help="the TCP port the controller will listen on for engine "
118 help="the TCP port the controller will listen on for engine "
119 "connections")
119 "connections")
120
120
121 newopt("--engine-ip", type="string", dest="engineip",
121 newopt("--engine-ip", type="string", dest="engineip",
122 help="the TCP ip address the controller will listen on "
122 help="the TCP ip address the controller will listen on "
123 "for engine connections")
123 "for engine connections")
124
124
125 newopt("--mpi", type="string", dest="mpi",
125 newopt("--mpi", type="string", dest="mpi",
126 help="use mpi with package: for instance --mpi=mpi4py")
126 help="use mpi with package: for instance --mpi=mpi4py")
127
127
128 newopt("-l", "--logfile", type="string", dest="logfile",
128 newopt("-l", "--logfile", type="string", dest="logfile",
129 help="log file name")
129 help="log file name")
130
130
131 newopt('-f','--cluster-file',dest='clusterfile',
131 newopt('-f','--cluster-file',dest='clusterfile',
132 help='file describing a remote cluster')
132 help='file describing a remote cluster')
133
133
134 return parser.parse_args()
134 return parser.parse_args()
135
135
136 def numAlive(controller,engines):
136 def numAlive(controller,engines):
137 """Return the number of processes still alive."""
137 """Return the number of processes still alive."""
138 retcodes = [controller.poll()] + \
138 retcodes = [controller.poll()] + \
139 [e.poll() for e in engines]
139 [e.poll() for e in engines]
140 return retcodes.count(None)
140 return retcodes.count(None)
141
141
142 stop = lambda pid: os.kill(pid,signal.SIGINT)
142 stop = lambda pid: os.kill(pid,signal.SIGINT)
143 kill = lambda pid: os.kill(pid,signal.SIGTERM)
143 kill = lambda pid: os.kill(pid,signal.SIGTERM)
144
144
145 def cleanup(clean,controller,engines):
145 def cleanup(clean,controller,engines):
146 """Stop the controller and engines with the given cleanup method."""
146 """Stop the controller and engines with the given cleanup method."""
147
147
148 for e in engines:
148 for e in engines:
149 if e.poll() is None:
149 if e.poll() is None:
150 print 'Stopping engine, pid',e.pid
150 print 'Stopping engine, pid',e.pid
151 clean(e.pid)
151 clean(e.pid)
152 if controller.poll() is None:
152 if controller.poll() is None:
153 print 'Stopping controller, pid',controller.pid
153 print 'Stopping controller, pid',controller.pid
154 clean(controller.pid)
154 clean(controller.pid)
155
155
156
156
157 def ensureDir(path):
157 def ensureDir(path):
158 """Ensure a directory exists or raise an exception."""
158 """Ensure a directory exists or raise an exception."""
159 if not os.path.isdir(path):
159 if not os.path.isdir(path):
160 os.makedirs(path)
160 os.makedirs(path)
161
161
162
162
163 def startMsg(control_host,control_port=10105):
163 def startMsg(control_host,control_port=10105):
164 """Print a startup message"""
164 """Print a startup message"""
165 print
165 print
166 print 'Your cluster is up and running.'
166 print 'Your cluster is up and running.'
167 print
167 print
168 print 'For interactive use, you can make a MultiEngineClient with:'
168 print 'For interactive use, you can make a MultiEngineClient with:'
169 print
169 print
170 print 'from IPython.kernel import client'
170 print 'from IPython.kernel import client'
171 print "mec = client.MultiEngineClient()"
171 print "mec = client.MultiEngineClient()"
172 print
172 print
173 print 'You can then cleanly stop the cluster from IPython using:'
173 print 'You can then cleanly stop the cluster from IPython using:'
174 print
174 print
175 print 'mec.kill(controller=True)'
175 print 'mec.kill(controller=True)'
176 print
176 print
177
177
178
178
179 def clusterLocal(opt,arg):
179 def clusterLocal(opt,arg):
180 """Start a cluster on the local machine."""
180 """Start a cluster on the local machine."""
181
181
182 # Store all logs inside the ipython directory
182 # Store all logs inside the ipython directory
183 ipdir = get_ipython_dir()
183 ipdir = get_ipython_dir()
184 pjoin = os.path.join
184 pjoin = os.path.join
185
185
186 logfile = opt.logfile
186 logfile = opt.logfile
187 if logfile is None:
187 if logfile is None:
188 logdir_base = pjoin(ipdir,'log')
188 logdir_base = pjoin(ipdir,'log')
189 ensureDir(logdir_base)
189 ensureDir(logdir_base)
190 logfile = pjoin(logdir_base,'ipcluster-')
190 logfile = pjoin(logdir_base,'ipcluster-')
191
191
192 print 'Starting controller:',
192 print 'Starting controller:',
193 controller = Popen(['ipcontroller','--logfile',logfile,'-x','-y'])
193 controller = Popen(['ipcontroller','--logfile',logfile,'-x','-y'])
194 print 'Controller PID:',controller.pid
194 print 'Controller PID:',controller.pid
195
195
196 print 'Starting engines: ',
196 print 'Starting engines: ',
197 time.sleep(5)
197 time.sleep(5)
198
198
199 englogfile = '%s%s-' % (logfile,controller.pid)
199 englogfile = '%s%s-' % (logfile,controller.pid)
200 mpi = opt.mpi
200 mpi = opt.mpi
201 if mpi: # start with mpi - killing the engines with sigterm will not work if you do this
201 if mpi: # start with mpi - killing the engines with sigterm will not work if you do this
202 engines = [Popen(['mpirun', '-np', str(opt.n), 'ipengine', '--mpi',
202 engines = [Popen(['mpirun', '-np', str(opt.n), 'ipengine', '--mpi',
203 mpi, '--logfile',englogfile])]
203 mpi, '--logfile',englogfile])]
204 # engines = [Popen(['mpirun', '-np', str(opt.n), 'ipengine', '--mpi', mpi])]
204 # engines = [Popen(['mpirun', '-np', str(opt.n), 'ipengine', '--mpi', mpi])]
205 else: # do what we would normally do
205 else: # do what we would normally do
206 engines = [ Popen(['ipengine','--logfile',englogfile])
206 engines = [ Popen(['ipengine','--logfile',englogfile])
207 for i in range(opt.n) ]
207 for i in range(opt.n) ]
208 eids = [e.pid for e in engines]
208 eids = [e.pid for e in engines]
209 print 'Engines PIDs: ',eids
209 print 'Engines PIDs: ',eids
210 print 'Log files: %s*' % englogfile
210 print 'Log files: %s*' % englogfile
211
211
212 proc_ids = eids + [controller.pid]
212 proc_ids = eids + [controller.pid]
213 procs = engines + [controller]
213 procs = engines + [controller]
214
214
215 grpid = os.getpgrp()
215 grpid = os.getpgrp()
216 try:
216 try:
217 startMsg('127.0.0.1')
217 startMsg('127.0.0.1')
218 print 'You can also hit Ctrl-C to stop it, or use from the cmd line:'
218 print 'You can also hit Ctrl-C to stop it, or use from the cmd line:'
219 print
219 print
220 print 'kill -INT',grpid
220 print 'kill -INT',grpid
221 print
221 print
222 try:
222 try:
223 while True:
223 while True:
224 time.sleep(5)
224 time.sleep(5)
225 except:
225 except:
226 pass
226 pass
227 finally:
227 finally:
228 print 'Stopping cluster. Cleaning up...'
228 print 'Stopping cluster. Cleaning up...'
229 cleanup(stop,controller,engines)
229 cleanup(stop,controller,engines)
230 for i in range(4):
230 for i in range(4):
231 time.sleep(i+2)
231 time.sleep(i+2)
232 nZombies = numAlive(controller,engines)
232 nZombies = numAlive(controller,engines)
233 if nZombies== 0:
233 if nZombies== 0:
234 print 'OK: All processes cleaned up.'
234 print 'OK: All processes cleaned up.'
235 break
235 break
236 print 'Trying again, %d processes did not stop...' % nZombies
236 print 'Trying again, %d processes did not stop...' % nZombies
237 cleanup(kill,controller,engines)
237 cleanup(kill,controller,engines)
238 if numAlive(controller,engines) == 0:
238 if numAlive(controller,engines) == 0:
239 print 'OK: All processes cleaned up.'
239 print 'OK: All processes cleaned up.'
240 break
240 break
241 else:
241 else:
242 print '*'*75
242 print '*'*75
243 print 'ERROR: could not kill some processes, try to do it',
243 print 'ERROR: could not kill some processes, try to do it',
244 print 'manually.'
244 print 'manually.'
245 zombies = []
245 zombies = []
246 if controller.returncode is None:
246 if controller.returncode is None:
247 print 'Controller is alive: pid =',controller.pid
247 print 'Controller is alive: pid =',controller.pid
248 zombies.append(controller.pid)
248 zombies.append(controller.pid)
249 liveEngines = [ e for e in engines if e.returncode is None ]
249 liveEngines = [ e for e in engines if e.returncode is None ]
250 for e in liveEngines:
250 for e in liveEngines:
251 print 'Engine is alive: pid =',e.pid
251 print 'Engine is alive: pid =',e.pid
252 zombies.append(e.pid)
252 zombies.append(e.pid)
253 print
253 print
254 print 'Zombie summary:',' '.join(map(str,zombies))
254 print 'Zombie summary:',' '.join(map(str,zombies))
255
255
256 def clusterRemote(opt,arg):
256 def clusterRemote(opt,arg):
257 """Start a remote cluster over SSH"""
257 """Start a remote cluster over SSH"""
258
258
259 # B. Granger, 9/3/08
259 # B. Granger, 9/3/08
260 # The launching of a remote cluster using SSH and a clusterfile
260 # The launching of a remote cluster using SSH and a clusterfile
261 # is broken. Because it won't be fixed before the 0.9 release,
261 # is broken. Because it won't be fixed before the 0.9 release,
262 # we are removing it. For now, we just print a message to the
262 # we are removing it. For now, we just print a message to the
263 # user and abort.
263 # user and abort.
264
264
265 print """The launching of a remote IPython cluster using SSL
265 print """The launching of a remote IPython cluster using SSL
266 and a clusterfile has been removed in this release.
266 and a clusterfile has been removed in this release.
267 It has been broken for a while and we are in the process
267 It has been broken for a while and we are in the process
268 of building a new process management system that will be
268 of building a new process management system that will be
269 used to provide a more robust way of starting an IPython
269 used to provide a more robust way of starting an IPython
270 cluster.
270 cluster.
271
271
272 For now remote clusters have to be launched using ipcontroller
272 For now remote clusters have to be launched using ipcontroller
273 and ipengine separately.
273 and ipengine separately.
274 """
274 """
275 sys.exit(1)
275 sys.exit(1)
276
276
277 # Load the remote cluster configuration
277 # Load the remote cluster configuration
278 clConfig = {}
278 clConfig = {}
279 execfile(opt.clusterfile,clConfig)
279 execfile(opt.clusterfile,clConfig)
280 contConfig = clConfig['controller']
280 contConfig = clConfig['controller']
281 engConfig = clConfig['engines']
281 engConfig = clConfig['engines']
282 # Determine where to find sshx:
282 # Determine where to find sshx:
283 sshx = clConfig.get('sshx',os.environ.get('IPYTHON_SSHX','sshx'))
283 sshx = clConfig.get('sshx',os.environ.get('IPYTHON_SSHX','sshx'))
284
284
285 # Store all logs inside the ipython directory
285 # Store all logs inside the ipython directory
286 ipdir = get_ipython_dir()
286 ipdir = get_ipython_dir()
287 pjoin = os.path.join
287 pjoin = os.path.join
288
288
289 logfile = opt.logfile
289 logfile = opt.logfile
290 if logfile is None:
290 if logfile is None:
291 logdir_base = pjoin(ipdir,'log')
291 logdir_base = pjoin(ipdir,'log')
292 ensureDir(logdir_base)
292 ensureDir(logdir_base)
293 logfile = pjoin(logdir_base,'ipcluster')
293 logfile = pjoin(logdir_base,'ipcluster')
294
294
295 # Append this script's PID to the logfile name always
295 # Append this script's PID to the logfile name always
296 logfile = '%s-%s' % (logfile,os.getpid())
296 logfile = '%s-%s' % (logfile,os.getpid())
297
297
298 print 'Starting controller:'
298 print 'Starting controller:'
299 # Controller data:
299 # Controller data:
300 xsys = os.system
300 xsys = os.system
301
301
302 contHost = contConfig['host']
302 contHost = contConfig['host']
303 contLog = '%s-con-%s-' % (logfile,contHost)
303 contLog = '%s-con-%s-' % (logfile,contHost)
304 cmd = "ssh %s '%s' 'ipcontroller --logfile %s' &" % \
304 cmd = "ssh %s '%s' 'ipcontroller --logfile %s' &" % \
305 (contHost,sshx,contLog)
305 (contHost,sshx,contLog)
306 #print 'cmd:<%s>' % cmd # dbg
306 #print 'cmd:<%s>' % cmd # dbg
307 xsys(cmd)
307 xsys(cmd)
308 time.sleep(2)
308 time.sleep(2)
309
309
310 print 'Starting engines: '
310 print 'Starting engines: '
311 for engineHost,engineData in engConfig.iteritems():
311 for engineHost,engineData in engConfig.iteritems():
312 if isinstance(engineData,int):
312 if isinstance(engineData,int):
313 numEngines = engineData
313 numEngines = engineData
314 else:
314 else:
315 raise NotImplementedError('port configuration not finished for engines')
315 raise NotImplementedError('port configuration not finished for engines')
316
316
317 print 'Sarting %d engines on %s' % (numEngines,engineHost)
317 print 'Sarting %d engines on %s' % (numEngines,engineHost)
318 engLog = '%s-eng-%s-' % (logfile,engineHost)
318 engLog = '%s-eng-%s-' % (logfile,engineHost)
319 for i in range(numEngines):
319 for i in range(numEngines):
320 cmd = "ssh %s '%s' 'ipengine --controller-ip %s --logfile %s' &" % \
320 cmd = "ssh %s '%s' 'ipengine --controller-ip %s --logfile %s' &" % \
321 (engineHost,sshx,contHost,engLog)
321 (engineHost,sshx,contHost,engLog)
322 #print 'cmd:<%s>' % cmd # dbg
322 #print 'cmd:<%s>' % cmd # dbg
323 xsys(cmd)
323 xsys(cmd)
324 # Wait after each host a little bit
324 # Wait after each host a little bit
325 time.sleep(1)
325 time.sleep(1)
326
326
327 startMsg(contConfig['host'])
327 startMsg(contConfig['host'])
328
328
329 def main():
329 def main():
330 """Main driver for the two big options: local or remote cluster."""
330 """Main driver for the two big options: local or remote cluster."""
331
331
332 if sys.platform=='win32':
333 print """ipcluster does not work on Microsoft Windows. Please start
334 your IPython cluster using the ipcontroller and ipengine scripts."""
335 sys.exit(1)
336
332 opt,arg = parse_args()
337 opt,arg = parse_args()
333
338
334 clusterfile = opt.clusterfile
339 clusterfile = opt.clusterfile
335 if clusterfile:
340 if clusterfile:
336 clusterRemote(opt,arg)
341 clusterRemote(opt,arg)
337 else:
342 else:
338 clusterLocal(opt,arg)
343 clusterLocal(opt,arg)
339
344
340
345
341 if __name__=='__main__':
346 if __name__=='__main__':
342 main()
347 main()
@@ -1,105 +1,106 b''
1 #!python
1 #!python
2 """Windows-specific part of the installation"""
2 """Windows-specific part of the installation"""
3
3
4 import os, sys, shutil
4 import os, sys, shutil
5 pjoin = os.path.join
5 pjoin = os.path.join
6
6
7 def mkshortcut(target,description,link_file,*args,**kw):
7 def mkshortcut(target,description,link_file,*args,**kw):
8 """make a shortcut if it doesn't exist, and register its creation"""
8 """make a shortcut if it doesn't exist, and register its creation"""
9
9
10 create_shortcut(target, description, link_file,*args,**kw)
10 create_shortcut(target, description, link_file,*args,**kw)
11 file_created(link_file)
11 file_created(link_file)
12
12
13 def install():
13 def install():
14 """Routine to be run by the win32 installer with the -install switch."""
14 """Routine to be run by the win32 installer with the -install switch."""
15
15
16 from IPython.Release import version
16 from IPython.Release import version
17
17
18 # Get some system constants
18 # Get some system constants
19 prefix = sys.prefix
19 prefix = sys.prefix
20 python = pjoin(prefix, 'python.exe')
20 python = pjoin(prefix, 'python.exe')
21
21
22 # Lookup path to common startmenu ...
22 # Lookup path to common startmenu ...
23 ip_start_menu = pjoin(get_special_folder_path('CSIDL_COMMON_PROGRAMS'), 'IPython')
23 ip_start_menu = pjoin(get_special_folder_path('CSIDL_COMMON_PROGRAMS'), 'IPython')
24 # Create IPython entry ...
24 # Create IPython entry ...
25 if not os.path.isdir(ip_start_menu):
25 if not os.path.isdir(ip_start_menu):
26 os.mkdir(ip_start_menu)
26 os.mkdir(ip_start_menu)
27 directory_created(ip_start_menu)
27 directory_created(ip_start_menu)
28
28
29 # Create .py and .bat files to make things available from
29 # Create .py and .bat files to make things available from
30 # the Windows command line
30 # the Windows command line. Thanks to the Twisted project
31 # for this logic!
31 programs = [
32 programs = [
32 'ipython',
33 'ipython',
33 'iptest',
34 'iptest',
34 'ipcontroller',
35 'ipcontroller',
35 'ipengine',
36 'ipengine',
36 'ipcluster',
37 'ipcluster',
37 'ipythonx',
38 'ipythonx',
38 'ipython-wx',
39 'ipython-wx',
39 'irunner'
40 'irunner'
40 ]
41 ]
41 scripts = pjoin(prefix,'scripts')
42 scripts = pjoin(prefix,'scripts')
42 for program in programs:
43 for program in programs:
43 raw = pjoin(scripts, program)
44 raw = pjoin(scripts, program)
44 bat = raw + '.bat'
45 bat = raw + '.bat'
45 py = raw + '.py'
46 py = raw + '.py'
46 # Create .py versions of the scripts
47 # Create .py versions of the scripts
47 shutil.copy(raw, py)
48 shutil.copy(raw, py)
48 # Create .bat files for each of the scripts
49 # Create .bat files for each of the scripts
49 bat_file = file(bat,'w')
50 bat_file = file(bat,'w')
50 bat_file.write("@%s %s %%*" % (python, py))
51 bat_file.write("@%s %s %%*" % (python, py))
51 bat_file.close()
52 bat_file.close()
52
53
53 # Now move onto setting the Start Menu up
54 # Now move onto setting the Start Menu up
54 ipybase = pjoin(scripts, 'ipython')
55 ipybase = pjoin(scripts, 'ipython')
55
56
56 link = pjoin(ip_start_menu, 'IPython.lnk')
57 link = pjoin(ip_start_menu, 'IPython.lnk')
57 cmd = '"%s"' % ipybase
58 cmd = '"%s"' % ipybase
58 mkshortcut(python,'IPython',link,cmd)
59 mkshortcut(python,'IPython',link,cmd)
59
60
60 link = pjoin(ip_start_menu, 'pysh.lnk')
61 link = pjoin(ip_start_menu, 'pysh.lnk')
61 cmd = '"%s" -p sh' % ipybase
62 cmd = '"%s" -p sh' % ipybase
62 mkshortcut(python,'IPython (command prompt mode)',link,cmd)
63 mkshortcut(python,'IPython (command prompt mode)',link,cmd)
63
64
64 link = pjoin(ip_start_menu, 'pylab.lnk')
65 link = pjoin(ip_start_menu, 'pylab.lnk')
65 cmd = '"%s" -pylab' % ipybase
66 cmd = '"%s" -pylab' % ipybase
66 mkshortcut(python,'IPython (PyLab mode)',link,cmd)
67 mkshortcut(python,'IPython (PyLab mode)',link,cmd)
67
68
68 link = pjoin(ip_start_menu, 'scipy.lnk')
69 link = pjoin(ip_start_menu, 'scipy.lnk')
69 cmd = '"%s" -pylab -p scipy' % ipybase
70 cmd = '"%s" -pylab -p scipy' % ipybase
70 mkshortcut(python,'IPython (scipy profile)',link,cmd)
71 mkshortcut(python,'IPython (scipy profile)',link,cmd)
71
72
72 link = pjoin(ip_start_menu, 'IPython test suite.lnk')
73 link = pjoin(ip_start_menu, 'IPython test suite.lnk')
73 cmd = '"%s" -vv' % pjoin(scripts, 'iptest')
74 cmd = '"%s" -vv' % pjoin(scripts, 'iptest')
74 mkshortcut(python,'Run the IPython test suite',link,cmd)
75 mkshortcut(python,'Run the IPython test suite',link,cmd)
75
76
76 link = pjoin(ip_start_menu, 'ipcontroller.lnk')
77 link = pjoin(ip_start_menu, 'ipcontroller.lnk')
77 cmd = '"%s" -xy' % pjoin(scripts, 'ipcontroller')
78 cmd = '"%s" -xy' % pjoin(scripts, 'ipcontroller')
78 mkshortcut(python,'IPython controller',link,cmd)
79 mkshortcut(python,'IPython controller',link,cmd)
79
80
80 link = pjoin(ip_start_menu, 'ipengine.lnk')
81 link = pjoin(ip_start_menu, 'ipengine.lnk')
81 cmd = '"%s"' % pjoin(scripts, 'ipengine')
82 cmd = '"%s"' % pjoin(scripts, 'ipengine')
82 mkshortcut(python,'IPython engine',link,cmd)
83 mkshortcut(python,'IPython engine',link,cmd)
83
84
84 # Create documentation shortcuts ...
85 # Create documentation shortcuts ...
85 t = prefix + r'\share\doc\ipython\manual\ipython.pdf'
86 t = prefix + r'\share\doc\ipython\manual\ipython.pdf'
86 f = ip_start_menu + r'\Manual in PDF.lnk'
87 f = ip_start_menu + r'\Manual in PDF.lnk'
87 mkshortcut(t,r'IPython Manual - PDF-Format',f)
88 mkshortcut(t,r'IPython Manual - PDF-Format',f)
88
89
89 t = prefix + r'\share\doc\ipython\manual\html\index.html'
90 t = prefix + r'\share\doc\ipython\manual\html\index.html'
90 f = ip_start_menu + r'\Manual in HTML.lnk'
91 f = ip_start_menu + r'\Manual in HTML.lnk'
91 mkshortcut(t,'IPython Manual - HTML-Format',f)
92 mkshortcut(t,'IPython Manual - HTML-Format',f)
92
93
93
94
94 def remove():
95 def remove():
95 """Routine to be run by the win32 installer with the -remove switch."""
96 """Routine to be run by the win32 installer with the -remove switch."""
96 pass
97 pass
97
98
98 # main()
99 # main()
99 if len(sys.argv) > 1:
100 if len(sys.argv) > 1:
100 if sys.argv[1] == '-install':
101 if sys.argv[1] == '-install':
101 install()
102 install()
102 elif sys.argv[1] == '-remove':
103 elif sys.argv[1] == '-remove':
103 remove()
104 remove()
104 else:
105 else:
105 print "Script was called with option %s" % sys.argv[1]
106 print "Script was called with option %s" % sys.argv[1]
General Comments 0
You need to be logged in to leave comments. Login now