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