##// END OF EJS Templates
remove unused check_for_readline
Min RK -
Show More
@@ -1,291 +1,290 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
2 # -*- coding: utf-8 -*-
3 """Setup script for IPython.
3 """Setup script for IPython.
4
4
5 Under Posix environments it works like a typical setup.py script.
5 Under Posix environments it works like a typical setup.py script.
6 Under Windows, the command sdist is not supported, since IPython
6 Under Windows, the command sdist is not supported, since IPython
7 requires utilities which are not available under Windows."""
7 requires utilities which are not available under Windows."""
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (c) 2008-2011, IPython Development Team.
10 # Copyright (c) 2008-2011, IPython Development Team.
11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
14 #
14 #
15 # Distributed under the terms of the Modified BSD License.
15 # Distributed under the terms of the Modified BSD License.
16 #
16 #
17 # The full license is in the file COPYING.rst, distributed with this software.
17 # The full license is in the file COPYING.rst, distributed with this software.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Minimal Python version sanity check
21 # Minimal Python version sanity check
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 from __future__ import print_function
23 from __future__ import print_function
24
24
25 import sys
25 import sys
26
26
27 # This check is also made in IPython/__init__, don't forget to update both when
27 # This check is also made in IPython/__init__, don't forget to update both when
28 # changing Python version requirements.
28 # changing Python version requirements.
29 v = sys.version_info
29 v = sys.version_info
30 if v[:2] < (2,7) or (v[0] >= 3 and v[:2] < (3,3)):
30 if v[:2] < (2,7) or (v[0] >= 3 and v[:2] < (3,3)):
31 error = "ERROR: IPython requires Python version 2.7 or 3.3 or above."
31 error = "ERROR: IPython requires Python version 2.7 or 3.3 or above."
32 print(error, file=sys.stderr)
32 print(error, file=sys.stderr)
33 sys.exit(1)
33 sys.exit(1)
34
34
35 PY3 = (sys.version_info[0] >= 3)
35 PY3 = (sys.version_info[0] >= 3)
36
36
37 # At least we're on the python version we need, move on.
37 # At least we're on the python version we need, move on.
38
38
39 #-------------------------------------------------------------------------------
39 #-------------------------------------------------------------------------------
40 # Imports
40 # Imports
41 #-------------------------------------------------------------------------------
41 #-------------------------------------------------------------------------------
42
42
43 # Stdlib imports
43 # Stdlib imports
44 import os
44 import os
45 import shutil
45 import shutil
46
46
47 from glob import glob
47 from glob import glob
48
48
49 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
49 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
50 # update it when the contents of directories change.
50 # update it when the contents of directories change.
51 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
51 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
52
52
53 from distutils.core import setup
53 from distutils.core import setup
54
54
55 # Our own imports
55 # Our own imports
56 from setupbase import target_update
56 from setupbase import target_update
57
57
58 from setupbase import (
58 from setupbase import (
59 setup_args,
59 setup_args,
60 find_packages,
60 find_packages,
61 find_package_data,
61 find_package_data,
62 check_package_data_first,
62 check_package_data_first,
63 find_entry_points,
63 find_entry_points,
64 build_scripts_entrypt,
64 build_scripts_entrypt,
65 find_data_files,
65 find_data_files,
66 check_for_readline,
67 git_prebuild,
66 git_prebuild,
68 install_symlinked,
67 install_symlinked,
69 install_lib_symlink,
68 install_lib_symlink,
70 install_scripts_for_symlink,
69 install_scripts_for_symlink,
71 unsymlink,
70 unsymlink,
72 )
71 )
73
72
74 isfile = os.path.isfile
73 isfile = os.path.isfile
75 pjoin = os.path.join
74 pjoin = os.path.join
76
75
77 #-------------------------------------------------------------------------------
76 #-------------------------------------------------------------------------------
78 # Handle OS specific things
77 # Handle OS specific things
79 #-------------------------------------------------------------------------------
78 #-------------------------------------------------------------------------------
80
79
81 if os.name in ('nt','dos'):
80 if os.name in ('nt','dos'):
82 os_name = 'windows'
81 os_name = 'windows'
83 else:
82 else:
84 os_name = os.name
83 os_name = os.name
85
84
86 # Under Windows, 'sdist' has not been supported. Now that the docs build with
85 # Under Windows, 'sdist' has not been supported. Now that the docs build with
87 # Sphinx it might work, but let's not turn it on until someone confirms that it
86 # Sphinx it might work, but let's not turn it on until someone confirms that it
88 # actually works.
87 # actually works.
89 if os_name == 'windows' and 'sdist' in sys.argv:
88 if os_name == 'windows' and 'sdist' in sys.argv:
90 print('The sdist command is not available under Windows. Exiting.')
89 print('The sdist command is not available under Windows. Exiting.')
91 sys.exit(1)
90 sys.exit(1)
92
91
93
92
94 #-------------------------------------------------------------------------------
93 #-------------------------------------------------------------------------------
95 # Things related to the IPython documentation
94 # Things related to the IPython documentation
96 #-------------------------------------------------------------------------------
95 #-------------------------------------------------------------------------------
97
96
98 # update the manuals when building a source dist
97 # update the manuals when building a source dist
99 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
98 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
100
99
101 # List of things to be updated. Each entry is a triplet of args for
100 # List of things to be updated. Each entry is a triplet of args for
102 # target_update()
101 # target_update()
103 to_update = [
102 to_update = [
104 ('docs/man/ipython.1.gz',
103 ('docs/man/ipython.1.gz',
105 ['docs/man/ipython.1'],
104 ['docs/man/ipython.1'],
106 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
105 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
107 ]
106 ]
108
107
109
108
110 [ target_update(*t) for t in to_update ]
109 [ target_update(*t) for t in to_update ]
111
110
112 #---------------------------------------------------------------------------
111 #---------------------------------------------------------------------------
113 # Find all the packages, package data, and data_files
112 # Find all the packages, package data, and data_files
114 #---------------------------------------------------------------------------
113 #---------------------------------------------------------------------------
115
114
116 packages = find_packages()
115 packages = find_packages()
117 package_data = find_package_data()
116 package_data = find_package_data()
118
117
119 data_files = find_data_files()
118 data_files = find_data_files()
120
119
121 setup_args['packages'] = packages
120 setup_args['packages'] = packages
122 setup_args['package_data'] = package_data
121 setup_args['package_data'] = package_data
123 setup_args['data_files'] = data_files
122 setup_args['data_files'] = data_files
124
123
125 #---------------------------------------------------------------------------
124 #---------------------------------------------------------------------------
126 # custom distutils commands
125 # custom distutils commands
127 #---------------------------------------------------------------------------
126 #---------------------------------------------------------------------------
128 # imports here, so they are after setuptools import if there was one
127 # imports here, so they are after setuptools import if there was one
129 from distutils.command.sdist import sdist
128 from distutils.command.sdist import sdist
130 from distutils.command.upload import upload
129 from distutils.command.upload import upload
131
130
132 class UploadWindowsInstallers(upload):
131 class UploadWindowsInstallers(upload):
133
132
134 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
133 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
135 user_options = upload.user_options + [
134 user_options = upload.user_options + [
136 ('files=', 'f', 'exe file (or glob) to upload')
135 ('files=', 'f', 'exe file (or glob) to upload')
137 ]
136 ]
138 def initialize_options(self):
137 def initialize_options(self):
139 upload.initialize_options(self)
138 upload.initialize_options(self)
140 meta = self.distribution.metadata
139 meta = self.distribution.metadata
141 base = '{name}-{version}'.format(
140 base = '{name}-{version}'.format(
142 name=meta.get_name(),
141 name=meta.get_name(),
143 version=meta.get_version()
142 version=meta.get_version()
144 )
143 )
145 self.files = os.path.join('dist', '%s.*.exe' % base)
144 self.files = os.path.join('dist', '%s.*.exe' % base)
146
145
147 def run(self):
146 def run(self):
148 for dist_file in glob(self.files):
147 for dist_file in glob(self.files):
149 self.upload_file('bdist_wininst', 'any', dist_file)
148 self.upload_file('bdist_wininst', 'any', dist_file)
150
149
151 setup_args['cmdclass'] = {
150 setup_args['cmdclass'] = {
152 'build_py': \
151 'build_py': \
153 check_package_data_first(git_prebuild('IPython')),
152 check_package_data_first(git_prebuild('IPython')),
154 'sdist' : git_prebuild('IPython', sdist),
153 'sdist' : git_prebuild('IPython', sdist),
155 'upload_wininst' : UploadWindowsInstallers,
154 'upload_wininst' : UploadWindowsInstallers,
156 'symlink': install_symlinked,
155 'symlink': install_symlinked,
157 'install_lib_symlink': install_lib_symlink,
156 'install_lib_symlink': install_lib_symlink,
158 'install_scripts_sym': install_scripts_for_symlink,
157 'install_scripts_sym': install_scripts_for_symlink,
159 'unsymlink': unsymlink,
158 'unsymlink': unsymlink,
160 }
159 }
161
160
162 ### Temporarily disable install while it's broken during the big split
161 ### Temporarily disable install while it's broken during the big split
163 from textwrap import dedent
162 from textwrap import dedent
164 from distutils.command.install import install
163 from distutils.command.install import install
165
164
166 class DisabledInstall(install):
165 class DisabledInstall(install):
167 def run(self):
166 def run(self):
168 msg = dedent("""
167 msg = dedent("""
169 While we are in the midst of The Big Split,
168 While we are in the midst of The Big Split,
170 IPython cannot be installed from master.
169 IPython cannot be installed from master.
171 You can use `pip install -e .` for an editable install,
170 You can use `pip install -e .` for an editable install,
172 which still works.
171 which still works.
173 """)
172 """)
174 print(msg, file=sys.stderr)
173 print(msg, file=sys.stderr)
175 raise SystemExit(1)
174 raise SystemExit(1)
176
175
177 setup_args['cmdclass']['install'] = DisabledInstall
176 setup_args['cmdclass']['install'] = DisabledInstall
178
177
179
178
180 #---------------------------------------------------------------------------
179 #---------------------------------------------------------------------------
181 # Handle scripts, dependencies, and setuptools specific things
180 # Handle scripts, dependencies, and setuptools specific things
182 #---------------------------------------------------------------------------
181 #---------------------------------------------------------------------------
183
182
184 # For some commands, use setuptools. Note that we do NOT list install here!
183 # For some commands, use setuptools. Note that we do NOT list install here!
185 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
184 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
186 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
185 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
187 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
186 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
188 'egg_info', 'easy_install', 'upload', 'install_egg_info',
187 'egg_info', 'easy_install', 'upload', 'install_egg_info',
189 ))
188 ))
190
189
191 if len(needs_setuptools.intersection(sys.argv)) > 0:
190 if len(needs_setuptools.intersection(sys.argv)) > 0:
192 import setuptools
191 import setuptools
193
192
194 # This dict is used for passing extra arguments that are setuptools
193 # This dict is used for passing extra arguments that are setuptools
195 # specific to setup
194 # specific to setup
196 setuptools_extra_args = {}
195 setuptools_extra_args = {}
197
196
198 # setuptools requirements
197 # setuptools requirements
199
198
200 extras_require = dict(
199 extras_require = dict(
201 parallel = ['ipyparallel'],
200 parallel = ['ipyparallel'],
202 qtconsole = ['qtconsole'],
201 qtconsole = ['qtconsole'],
203 doc = ['Sphinx>=1.1', 'numpydoc'],
202 doc = ['Sphinx>=1.1', 'numpydoc'],
204 test = ['nose>=0.10.1', 'requests', 'testpath'],
203 test = ['nose>=0.10.1', 'requests', 'testpath'],
205 terminal = [],
204 terminal = [],
206 kernel = ['ipykernel'],
205 kernel = ['ipykernel'],
207 nbformat = ['nbformat'],
206 nbformat = ['nbformat'],
208 notebook = ['notebook'],
207 notebook = ['notebook'],
209 nbconvert = ['nbconvert'],
208 nbconvert = ['nbconvert'],
210 )
209 )
211 install_requires = [
210 install_requires = [
212 'decorator',
211 'decorator',
213 'pickleshare',
212 'pickleshare',
214 'simplegeneric>0.8',
213 'simplegeneric>0.8',
215 'traitlets',
214 'traitlets',
216 ]
215 ]
217
216
218 # Platform-specific dependencies:
217 # Platform-specific dependencies:
219 # This is the correct way to specify these,
218 # This is the correct way to specify these,
220 # but requires pip >= 6. pip < 6 ignores these.
219 # but requires pip >= 6. pip < 6 ignores these.
221 extras_require.update({
220 extras_require.update({
222 ':sys_platform != "win32"': ['pexpect'],
221 ':sys_platform != "win32"': ['pexpect'],
223 ':sys_platform == "darwin"': ['appnope', 'gnureadline'],
222 ':sys_platform == "darwin"': ['appnope', 'gnureadline'],
224 'terminal:sys_platform == "win32"': ['pyreadline>=2'],
223 'terminal:sys_platform == "win32"': ['pyreadline>=2'],
225 'test:python_version == "2.7"': ['mock'],
224 'test:python_version == "2.7"': ['mock'],
226 })
225 })
227 # FIXME: re-specify above platform dependencies for pip < 6
226 # FIXME: re-specify above platform dependencies for pip < 6
228 # These would result in non-portable bdists.
227 # These would result in non-portable bdists.
229 if not any(arg.startswith('bdist') for arg in sys.argv):
228 if not any(arg.startswith('bdist') for arg in sys.argv):
230 if sys.version_info < (3, 3):
229 if sys.version_info < (3, 3):
231 extras_require['test'].append('mock')
230 extras_require['test'].append('mock')
232
231
233 if sys.platform == 'darwin':
232 if sys.platform == 'darwin':
234 install_requires.extend(['appnope', 'gnureadline'])
233 install_requires.extend(['appnope', 'gnureadline'])
235
234
236 if sys.platform.startswith('win'):
235 if sys.platform.startswith('win'):
237 extras_require['terminal'].append('pyreadline>=2.0')
236 extras_require['terminal'].append('pyreadline>=2.0')
238 else:
237 else:
239 install_requires.append('pexpect')
238 install_requires.append('pexpect')
240
239
241 everything = set()
240 everything = set()
242 for deps in extras_require.values():
241 for deps in extras_require.values():
243 everything.update(deps)
242 everything.update(deps)
244 extras_require['all'] = everything
243 extras_require['all'] = everything
245
244
246 if 'setuptools' in sys.modules:
245 if 'setuptools' in sys.modules:
247 setuptools_extra_args['zip_safe'] = False
246 setuptools_extra_args['zip_safe'] = False
248 setuptools_extra_args['entry_points'] = {
247 setuptools_extra_args['entry_points'] = {
249 'console_scripts': find_entry_points(),
248 'console_scripts': find_entry_points(),
250 'pygments.lexers': [
249 'pygments.lexers': [
251 'ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer',
250 'ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer',
252 'ipython = IPython.lib.lexers:IPythonLexer',
251 'ipython = IPython.lib.lexers:IPythonLexer',
253 'ipython3 = IPython.lib.lexers:IPython3Lexer',
252 'ipython3 = IPython.lib.lexers:IPython3Lexer',
254 ],
253 ],
255 }
254 }
256 setup_args['extras_require'] = extras_require
255 setup_args['extras_require'] = extras_require
257 requires = setup_args['install_requires'] = install_requires
256 requires = setup_args['install_requires'] = install_requires
258
257
259 # Script to be run by the windows binary installer after the default setup
258 # Script to be run by the windows binary installer after the default setup
260 # routine, to add shortcuts and similar windows-only things. Windows
259 # routine, to add shortcuts and similar windows-only things. Windows
261 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
260 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
262 # doesn't find them.
261 # doesn't find them.
263 if 'bdist_wininst' in sys.argv:
262 if 'bdist_wininst' in sys.argv:
264 if len(sys.argv) > 2 and \
263 if len(sys.argv) > 2 and \
265 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
264 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
266 print("ERROR: bdist_wininst must be run alone. Exiting.", file=sys.stderr)
265 print("ERROR: bdist_wininst must be run alone. Exiting.", file=sys.stderr)
267 sys.exit(1)
266 sys.exit(1)
268 setup_args['data_files'].append(
267 setup_args['data_files'].append(
269 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
268 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
270 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
269 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
271 setup_args['options'] = {"bdist_wininst":
270 setup_args['options'] = {"bdist_wininst":
272 {"install_script":
271 {"install_script":
273 "ipython_win_post_install.py"}}
272 "ipython_win_post_install.py"}}
274
273
275 else:
274 else:
276 # scripts has to be a non-empty list, or install_scripts isn't called
275 # scripts has to be a non-empty list, or install_scripts isn't called
277 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
276 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
278
277
279 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
278 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
280
279
281 #---------------------------------------------------------------------------
280 #---------------------------------------------------------------------------
282 # Do the actual setup now
281 # Do the actual setup now
283 #---------------------------------------------------------------------------
282 #---------------------------------------------------------------------------
284
283
285 setup_args.update(setuptools_extra_args)
284 setup_args.update(setuptools_extra_args)
286
285
287 def main():
286 def main():
288 setup(**setup_args)
287 setup(**setup_args)
289
288
290 if __name__ == '__main__':
289 if __name__ == '__main__':
291 main()
290 main()
@@ -1,487 +1,466 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
11
12 # Copyright (c) IPython Development Team.
12 # Copyright (c) IPython Development Team.
13 # Distributed under the terms of the Modified BSD License.
13 # Distributed under the terms of the Modified BSD License.
14
14
15 from __future__ import print_function
15 from __future__ import print_function
16
16
17 import errno
17 import errno
18 import os
18 import os
19 import sys
19 import sys
20
20
21 from distutils import log
21 from distutils import log
22 from distutils.command.build_py import build_py
22 from distutils.command.build_py import build_py
23 from distutils.command.build_scripts import build_scripts
23 from distutils.command.build_scripts import build_scripts
24 from distutils.command.install import install
24 from distutils.command.install import install
25 from distutils.command.install_scripts import install_scripts
25 from distutils.command.install_scripts import install_scripts
26 from distutils.cmd import Command
26 from distutils.cmd import Command
27 from distutils.errors import DistutilsExecError
27 from distutils.errors import DistutilsExecError
28 from fnmatch import fnmatch
28 from fnmatch import fnmatch
29 from glob import glob
29 from glob import glob
30 from subprocess import Popen, PIPE
30 from subprocess import Popen, PIPE
31
31
32 from setupext import install_data_ext
32 from setupext import install_data_ext
33
33
34 #-------------------------------------------------------------------------------
34 #-------------------------------------------------------------------------------
35 # Useful globals and utility functions
35 # Useful globals and utility functions
36 #-------------------------------------------------------------------------------
36 #-------------------------------------------------------------------------------
37
37
38 # A few handy globals
38 # A few handy globals
39 isfile = os.path.isfile
39 isfile = os.path.isfile
40 pjoin = os.path.join
40 pjoin = os.path.join
41 repo_root = os.path.dirname(os.path.abspath(__file__))
41 repo_root = os.path.dirname(os.path.abspath(__file__))
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 # Py3 compatibility hacks, without assuming IPython itself is installed with
47 # Py3 compatibility hacks, without assuming IPython itself is installed with
48 # the full py3compat machinery.
48 # the full py3compat machinery.
49
49
50 try:
50 try:
51 execfile
51 execfile
52 except NameError:
52 except NameError:
53 def execfile(fname, globs, locs=None):
53 def execfile(fname, globs, locs=None):
54 locs = locs or globs
54 locs = locs or globs
55 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
55 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
56
56
57 # A little utility we'll need below, since glob() does NOT allow you to do
57 # A little utility we'll need below, since glob() does NOT allow you to do
58 # exclusion on multiple endings!
58 # exclusion on multiple endings!
59 def file_doesnt_endwith(test,endings):
59 def file_doesnt_endwith(test,endings):
60 """Return true if test is a file and its name does NOT end with any
60 """Return true if test is a file and its name does NOT end with any
61 of the strings listed in endings."""
61 of the strings listed in endings."""
62 if not isfile(test):
62 if not isfile(test):
63 return False
63 return False
64 for e in endings:
64 for e in endings:
65 if test.endswith(e):
65 if test.endswith(e):
66 return False
66 return False
67 return True
67 return True
68
68
69 #---------------------------------------------------------------------------
69 #---------------------------------------------------------------------------
70 # Basic project information
70 # Basic project information
71 #---------------------------------------------------------------------------
71 #---------------------------------------------------------------------------
72
72
73 # release.py contains version, authors, license, url, keywords, etc.
73 # release.py contains version, authors, license, url, keywords, etc.
74 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
74 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
75
75
76 # Create a dict with the basic information
76 # Create a dict with the basic information
77 # This dict is eventually passed to setup after additional keys are added.
77 # This dict is eventually passed to setup after additional keys are added.
78 setup_args = dict(
78 setup_args = dict(
79 name = name,
79 name = name,
80 version = version,
80 version = version,
81 description = description,
81 description = description,
82 long_description = long_description,
82 long_description = long_description,
83 author = author,
83 author = author,
84 author_email = author_email,
84 author_email = author_email,
85 url = url,
85 url = url,
86 download_url = download_url,
86 download_url = download_url,
87 license = license,
87 license = license,
88 platforms = platforms,
88 platforms = platforms,
89 keywords = keywords,
89 keywords = keywords,
90 classifiers = classifiers,
90 classifiers = classifiers,
91 cmdclass = {'install_data': install_data_ext},
91 cmdclass = {'install_data': install_data_ext},
92 )
92 )
93
93
94
94
95 #---------------------------------------------------------------------------
95 #---------------------------------------------------------------------------
96 # Find packages
96 # Find packages
97 #---------------------------------------------------------------------------
97 #---------------------------------------------------------------------------
98
98
99 def find_packages():
99 def find_packages():
100 """
100 """
101 Find all of IPython's packages.
101 Find all of IPython's packages.
102 """
102 """
103 excludes = ['deathrow', 'quarantine']
103 excludes = ['deathrow', 'quarantine']
104 packages = []
104 packages = []
105 for dir,subdirs,files in os.walk('IPython'):
105 for dir,subdirs,files in os.walk('IPython'):
106 package = dir.replace(os.path.sep, '.')
106 package = dir.replace(os.path.sep, '.')
107 if any(package.startswith('IPython.'+exc) for exc in excludes):
107 if any(package.startswith('IPython.'+exc) for exc in excludes):
108 # package is to be excluded (e.g. deathrow)
108 # package is to be excluded (e.g. deathrow)
109 continue
109 continue
110 if '__init__.py' not in files:
110 if '__init__.py' not in files:
111 # not a package
111 # not a package
112 continue
112 continue
113 packages.append(package)
113 packages.append(package)
114 return packages
114 return packages
115
115
116 #---------------------------------------------------------------------------
116 #---------------------------------------------------------------------------
117 # Find package data
117 # Find package data
118 #---------------------------------------------------------------------------
118 #---------------------------------------------------------------------------
119
119
120 def find_package_data():
120 def find_package_data():
121 """
121 """
122 Find IPython's package_data.
122 Find IPython's package_data.
123 """
123 """
124 # This is not enough for these things to appear in an sdist.
124 # This is not enough for these things to appear in an sdist.
125 # We need to muck with the MANIFEST to get this to work
125 # We need to muck with the MANIFEST to get this to work
126
126
127 package_data = {
127 package_data = {
128 'IPython.core' : ['profile/README*'],
128 'IPython.core' : ['profile/README*'],
129 'IPython.core.tests' : ['*.png', '*.jpg'],
129 'IPython.core.tests' : ['*.png', '*.jpg'],
130 'IPython.lib.tests' : ['*.wav'],
130 'IPython.lib.tests' : ['*.wav'],
131 'IPython.testing.plugin' : ['*.txt'],
131 'IPython.testing.plugin' : ['*.txt'],
132 }
132 }
133
133
134 return package_data
134 return package_data
135
135
136
136
137 def check_package_data(package_data):
137 def check_package_data(package_data):
138 """verify that package_data globs make sense"""
138 """verify that package_data globs make sense"""
139 print("checking package data")
139 print("checking package data")
140 for pkg, data in package_data.items():
140 for pkg, data in package_data.items():
141 pkg_root = pjoin(*pkg.split('.'))
141 pkg_root = pjoin(*pkg.split('.'))
142 for d in data:
142 for d in data:
143 path = pjoin(pkg_root, d)
143 path = pjoin(pkg_root, d)
144 if '*' in path:
144 if '*' in path:
145 assert len(glob(path)) > 0, "No files match pattern %s" % path
145 assert len(glob(path)) > 0, "No files match pattern %s" % path
146 else:
146 else:
147 assert os.path.exists(path), "Missing package data: %s" % path
147 assert os.path.exists(path), "Missing package data: %s" % path
148
148
149
149
150 def check_package_data_first(command):
150 def check_package_data_first(command):
151 """decorator for checking package_data before running a given command
151 """decorator for checking package_data before running a given command
152
152
153 Probably only needs to wrap build_py
153 Probably only needs to wrap build_py
154 """
154 """
155 class DecoratedCommand(command):
155 class DecoratedCommand(command):
156 def run(self):
156 def run(self):
157 check_package_data(self.package_data)
157 check_package_data(self.package_data)
158 command.run(self)
158 command.run(self)
159 return DecoratedCommand
159 return DecoratedCommand
160
160
161
161
162 #---------------------------------------------------------------------------
162 #---------------------------------------------------------------------------
163 # Find data files
163 # Find data files
164 #---------------------------------------------------------------------------
164 #---------------------------------------------------------------------------
165
165
166 def make_dir_struct(tag,base,out_base):
166 def make_dir_struct(tag,base,out_base):
167 """Make the directory structure of all files below a starting dir.
167 """Make the directory structure of all files below a starting dir.
168
168
169 This is just a convenience routine to help build a nested directory
169 This is just a convenience routine to help build a nested directory
170 hierarchy because distutils is too stupid to do this by itself.
170 hierarchy because distutils is too stupid to do this by itself.
171
171
172 XXX - this needs a proper docstring!
172 XXX - this needs a proper docstring!
173 """
173 """
174
174
175 # we'll use these a lot below
175 # we'll use these a lot below
176 lbase = len(base)
176 lbase = len(base)
177 pathsep = os.path.sep
177 pathsep = os.path.sep
178 lpathsep = len(pathsep)
178 lpathsep = len(pathsep)
179
179
180 out = []
180 out = []
181 for (dirpath,dirnames,filenames) in os.walk(base):
181 for (dirpath,dirnames,filenames) in os.walk(base):
182 # we need to strip out the dirpath from the base to map it to the
182 # we need to strip out the dirpath from the base to map it to the
183 # output (installation) path. This requires possibly stripping the
183 # output (installation) path. This requires possibly stripping the
184 # path separator, because otherwise pjoin will not work correctly
184 # path separator, because otherwise pjoin will not work correctly
185 # (pjoin('foo/','/bar') returns '/bar').
185 # (pjoin('foo/','/bar') returns '/bar').
186
186
187 dp_eff = dirpath[lbase:]
187 dp_eff = dirpath[lbase:]
188 if dp_eff.startswith(pathsep):
188 if dp_eff.startswith(pathsep):
189 dp_eff = dp_eff[lpathsep:]
189 dp_eff = dp_eff[lpathsep:]
190 # The output path must be anchored at the out_base marker
190 # The output path must be anchored at the out_base marker
191 out_path = pjoin(out_base,dp_eff)
191 out_path = pjoin(out_base,dp_eff)
192 # Now we can generate the final filenames. Since os.walk only produces
192 # Now we can generate the final filenames. Since os.walk only produces
193 # filenames, we must join back with the dirpath to get full valid file
193 # filenames, we must join back with the dirpath to get full valid file
194 # paths:
194 # paths:
195 pfiles = [pjoin(dirpath,f) for f in filenames]
195 pfiles = [pjoin(dirpath,f) for f in filenames]
196 # Finally, generate the entry we need, which is a pari of (output
196 # Finally, generate the entry we need, which is a pari of (output
197 # path, files) for use as a data_files parameter in install_data.
197 # path, files) for use as a data_files parameter in install_data.
198 out.append((out_path, pfiles))
198 out.append((out_path, pfiles))
199
199
200 return out
200 return out
201
201
202
202
203 def find_data_files():
203 def find_data_files():
204 """
204 """
205 Find IPython's data_files.
205 Find IPython's data_files.
206
206
207 Just man pages at this point.
207 Just man pages at this point.
208 """
208 """
209
209
210 manpagebase = pjoin('share', 'man', 'man1')
210 manpagebase = pjoin('share', 'man', 'man1')
211
211
212 # Simple file lists can be made by hand
212 # Simple file lists can be made by hand
213 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
213 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
214 if not manpages:
214 if not manpages:
215 # When running from a source tree, the manpages aren't gzipped
215 # When running from a source tree, the manpages aren't gzipped
216 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
216 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
217
217
218 # And assemble the entire output list
218 # And assemble the entire output list
219 data_files = [ (manpagebase, manpages) ]
219 data_files = [ (manpagebase, manpages) ]
220
220
221 return data_files
221 return data_files
222
222
223
223
224 def make_man_update_target(manpage):
224 def make_man_update_target(manpage):
225 """Return a target_update-compliant tuple for the given manpage.
225 """Return a target_update-compliant tuple for the given manpage.
226
226
227 Parameters
227 Parameters
228 ----------
228 ----------
229 manpage : string
229 manpage : string
230 Name of the manpage, must include the section number (trailing number).
230 Name of the manpage, must include the section number (trailing number).
231
231
232 Example
232 Example
233 -------
233 -------
234
234
235 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
235 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
236 ('docs/man/ipython.1.gz',
236 ('docs/man/ipython.1.gz',
237 ['docs/man/ipython.1'],
237 ['docs/man/ipython.1'],
238 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
238 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
239 """
239 """
240 man_dir = pjoin('docs', 'man')
240 man_dir = pjoin('docs', 'man')
241 manpage_gz = manpage + '.gz'
241 manpage_gz = manpage + '.gz'
242 manpath = pjoin(man_dir, manpage)
242 manpath = pjoin(man_dir, manpage)
243 manpath_gz = pjoin(man_dir, manpage_gz)
243 manpath_gz = pjoin(man_dir, manpage_gz)
244 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
244 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
245 locals() )
245 locals() )
246 return (manpath_gz, [manpath], gz_cmd)
246 return (manpath_gz, [manpath], gz_cmd)
247
247
248 # The two functions below are copied from IPython.utils.path, so we don't need
248 # The two functions below are copied from IPython.utils.path, so we don't need
249 # to import IPython during setup, which fails on Python 3.
249 # to import IPython during setup, which fails on Python 3.
250
250
251 def target_outdated(target,deps):
251 def target_outdated(target,deps):
252 """Determine whether a target is out of date.
252 """Determine whether a target is out of date.
253
253
254 target_outdated(target,deps) -> 1/0
254 target_outdated(target,deps) -> 1/0
255
255
256 deps: list of filenames which MUST exist.
256 deps: list of filenames which MUST exist.
257 target: single filename which may or may not exist.
257 target: single filename which may or may not exist.
258
258
259 If target doesn't exist or is older than any file listed in deps, return
259 If target doesn't exist or is older than any file listed in deps, return
260 true, otherwise return false.
260 true, otherwise return false.
261 """
261 """
262 try:
262 try:
263 target_time = os.path.getmtime(target)
263 target_time = os.path.getmtime(target)
264 except os.error:
264 except os.error:
265 return 1
265 return 1
266 for dep in deps:
266 for dep in deps:
267 dep_time = os.path.getmtime(dep)
267 dep_time = os.path.getmtime(dep)
268 if dep_time > target_time:
268 if dep_time > target_time:
269 #print "For target",target,"Dep failed:",dep # dbg
269 #print "For target",target,"Dep failed:",dep # dbg
270 #print "times (dep,tar):",dep_time,target_time # dbg
270 #print "times (dep,tar):",dep_time,target_time # dbg
271 return 1
271 return 1
272 return 0
272 return 0
273
273
274
274
275 def target_update(target,deps,cmd):
275 def target_update(target,deps,cmd):
276 """Update a target with a given command given a list of dependencies.
276 """Update a target with a given command given a list of dependencies.
277
277
278 target_update(target,deps,cmd) -> runs cmd if target is outdated.
278 target_update(target,deps,cmd) -> runs cmd if target is outdated.
279
279
280 This is just a wrapper around target_outdated() which calls the given
280 This is just a wrapper around target_outdated() which calls the given
281 command if target is outdated."""
281 command if target is outdated."""
282
282
283 if target_outdated(target,deps):
283 if target_outdated(target,deps):
284 os.system(cmd)
284 os.system(cmd)
285
285
286 #---------------------------------------------------------------------------
286 #---------------------------------------------------------------------------
287 # Find scripts
287 # Find scripts
288 #---------------------------------------------------------------------------
288 #---------------------------------------------------------------------------
289
289
290 def find_entry_points():
290 def find_entry_points():
291 """Defines the command line entry points for IPython
291 """Defines the command line entry points for IPython
292
292
293 This always uses setuptools-style entry points. When setuptools is not in
293 This always uses setuptools-style entry points. When setuptools is not in
294 use, our own build_scripts_entrypt class below parses these and builds
294 use, our own build_scripts_entrypt class below parses these and builds
295 command line scripts.
295 command line scripts.
296
296
297 Each of our entry points gets both a plain name, e.g. ipython, and one
297 Each of our entry points gets both a plain name, e.g. ipython, and one
298 suffixed with the Python major version number, e.g. ipython3.
298 suffixed with the Python major version number, e.g. ipython3.
299 """
299 """
300 ep = [
300 ep = [
301 'ipython%s = IPython:start_ipython',
301 'ipython%s = IPython:start_ipython',
302 'iptest%s = IPython.testing.iptestcontroller:main',
302 'iptest%s = IPython.testing.iptestcontroller:main',
303 ]
303 ]
304 suffix = str(sys.version_info[0])
304 suffix = str(sys.version_info[0])
305 return [e % '' for e in ep] + [e % suffix for e in ep]
305 return [e % '' for e in ep] + [e % suffix for e in ep]
306
306
307 script_src = """#!{executable}
307 script_src = """#!{executable}
308 # This script was automatically generated by setup.py
308 # This script was automatically generated by setup.py
309 if __name__ == '__main__':
309 if __name__ == '__main__':
310 from {mod} import {func}
310 from {mod} import {func}
311 {func}()
311 {func}()
312 """
312 """
313
313
314 class build_scripts_entrypt(build_scripts):
314 class build_scripts_entrypt(build_scripts):
315 """Build the command line scripts
315 """Build the command line scripts
316
316
317 Parse setuptools style entry points and write simple scripts to run the
317 Parse setuptools style entry points and write simple scripts to run the
318 target functions.
318 target functions.
319
319
320 On Windows, this also creates .cmd wrappers for the scripts so that you can
320 On Windows, this also creates .cmd wrappers for the scripts so that you can
321 easily launch them from a command line.
321 easily launch them from a command line.
322 """
322 """
323 def run(self):
323 def run(self):
324 self.mkpath(self.build_dir)
324 self.mkpath(self.build_dir)
325 outfiles = []
325 outfiles = []
326 for script in find_entry_points():
326 for script in find_entry_points():
327 name, entrypt = script.split('=')
327 name, entrypt = script.split('=')
328 name = name.strip()
328 name = name.strip()
329 entrypt = entrypt.strip()
329 entrypt = entrypt.strip()
330 outfile = os.path.join(self.build_dir, name)
330 outfile = os.path.join(self.build_dir, name)
331 outfiles.append(outfile)
331 outfiles.append(outfile)
332 print('Writing script to', outfile)
332 print('Writing script to', outfile)
333
333
334 mod, func = entrypt.split(':')
334 mod, func = entrypt.split(':')
335 with open(outfile, 'w') as f:
335 with open(outfile, 'w') as f:
336 f.write(script_src.format(executable=sys.executable,
336 f.write(script_src.format(executable=sys.executable,
337 mod=mod, func=func))
337 mod=mod, func=func))
338
338
339 if sys.platform == 'win32':
339 if sys.platform == 'win32':
340 # Write .cmd wrappers for Windows so 'ipython' etc. work at the
340 # Write .cmd wrappers for Windows so 'ipython' etc. work at the
341 # command line
341 # command line
342 cmd_file = os.path.join(self.build_dir, name + '.cmd')
342 cmd_file = os.path.join(self.build_dir, name + '.cmd')
343 cmd = '@"{python}" "%~dp0\{script}" %*\r\n'.format(
343 cmd = '@"{python}" "%~dp0\{script}" %*\r\n'.format(
344 python=sys.executable, script=name)
344 python=sys.executable, script=name)
345 log.info("Writing %s wrapper script" % cmd_file)
345 log.info("Writing %s wrapper script" % cmd_file)
346 with open(cmd_file, 'w') as f:
346 with open(cmd_file, 'w') as f:
347 f.write(cmd)
347 f.write(cmd)
348
348
349 return outfiles, outfiles
349 return outfiles, outfiles
350
350
351 class install_lib_symlink(Command):
351 class install_lib_symlink(Command):
352 user_options = [
352 user_options = [
353 ('install-dir=', 'd', "directory to install to"),
353 ('install-dir=', 'd', "directory to install to"),
354 ]
354 ]
355
355
356 def initialize_options(self):
356 def initialize_options(self):
357 self.install_dir = None
357 self.install_dir = None
358
358
359 def finalize_options(self):
359 def finalize_options(self):
360 self.set_undefined_options('symlink',
360 self.set_undefined_options('symlink',
361 ('install_lib', 'install_dir'),
361 ('install_lib', 'install_dir'),
362 )
362 )
363
363
364 def run(self):
364 def run(self):
365 if sys.platform == 'win32':
365 if sys.platform == 'win32':
366 raise Exception("This doesn't work on Windows.")
366 raise Exception("This doesn't work on Windows.")
367 pkg = os.path.join(os.getcwd(), 'IPython')
367 pkg = os.path.join(os.getcwd(), 'IPython')
368 dest = os.path.join(self.install_dir, 'IPython')
368 dest = os.path.join(self.install_dir, 'IPython')
369 if os.path.islink(dest):
369 if os.path.islink(dest):
370 print('removing existing symlink at %s' % dest)
370 print('removing existing symlink at %s' % dest)
371 os.unlink(dest)
371 os.unlink(dest)
372 print('symlinking %s -> %s' % (pkg, dest))
372 print('symlinking %s -> %s' % (pkg, dest))
373 os.symlink(pkg, dest)
373 os.symlink(pkg, dest)
374
374
375 class unsymlink(install):
375 class unsymlink(install):
376 def run(self):
376 def run(self):
377 dest = os.path.join(self.install_lib, 'IPython')
377 dest = os.path.join(self.install_lib, 'IPython')
378 if os.path.islink(dest):
378 if os.path.islink(dest):
379 print('removing symlink at %s' % dest)
379 print('removing symlink at %s' % dest)
380 os.unlink(dest)
380 os.unlink(dest)
381 else:
381 else:
382 print('No symlink exists at %s' % dest)
382 print('No symlink exists at %s' % dest)
383
383
384 class install_symlinked(install):
384 class install_symlinked(install):
385 def run(self):
385 def run(self):
386 if sys.platform == 'win32':
386 if sys.platform == 'win32':
387 raise Exception("This doesn't work on Windows.")
387 raise Exception("This doesn't work on Windows.")
388
388
389 # Run all sub-commands (at least those that need to be run)
389 # Run all sub-commands (at least those that need to be run)
390 for cmd_name in self.get_sub_commands():
390 for cmd_name in self.get_sub_commands():
391 self.run_command(cmd_name)
391 self.run_command(cmd_name)
392
392
393 # 'sub_commands': a list of commands this command might have to run to
393 # 'sub_commands': a list of commands this command might have to run to
394 # get its work done. See cmd.py for more info.
394 # get its work done. See cmd.py for more info.
395 sub_commands = [('install_lib_symlink', lambda self:True),
395 sub_commands = [('install_lib_symlink', lambda self:True),
396 ('install_scripts_sym', lambda self:True),
396 ('install_scripts_sym', lambda self:True),
397 ]
397 ]
398
398
399 class install_scripts_for_symlink(install_scripts):
399 class install_scripts_for_symlink(install_scripts):
400 """Redefined to get options from 'symlink' instead of 'install'.
400 """Redefined to get options from 'symlink' instead of 'install'.
401
401
402 I love distutils almost as much as I love setuptools.
402 I love distutils almost as much as I love setuptools.
403 """
403 """
404 def finalize_options(self):
404 def finalize_options(self):
405 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
405 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
406 self.set_undefined_options('symlink',
406 self.set_undefined_options('symlink',
407 ('install_scripts', 'install_dir'),
407 ('install_scripts', 'install_dir'),
408 ('force', 'force'),
408 ('force', 'force'),
409 ('skip_build', 'skip_build'),
409 ('skip_build', 'skip_build'),
410 )
410 )
411
411
412 #---------------------------------------------------------------------------
413 # Verify all dependencies
414 #---------------------------------------------------------------------------
415
416 def check_for_readline():
417 """Check for GNU readline"""
418 try:
419 import gnureadline as readline
420 except ImportError:
421 pass
422 else:
423 return True
424 try:
425 import readline
426 except ImportError:
427 return False
428 else:
429 if sys.platform == 'darwin' and 'libedit' in readline.__doc__:
430 print("Ignoring readline linked to libedit", file=sys.stderr)
431 return False
432 return True
433
412
434 #---------------------------------------------------------------------------
413 #---------------------------------------------------------------------------
435 # VCS related
414 # VCS related
436 #---------------------------------------------------------------------------
415 #---------------------------------------------------------------------------
437
416
438
417
439 def git_prebuild(pkg_dir, build_cmd=build_py):
418 def git_prebuild(pkg_dir, build_cmd=build_py):
440 """Return extended build or sdist command class for recording commit
419 """Return extended build or sdist command class for recording commit
441
420
442 records git commit in IPython.utils._sysinfo.commit
421 records git commit in IPython.utils._sysinfo.commit
443
422
444 for use in IPython.utils.sysinfo.sys_info() calls after installation.
423 for use in IPython.utils.sysinfo.sys_info() calls after installation.
445 """
424 """
446
425
447 class MyBuildPy(build_cmd):
426 class MyBuildPy(build_cmd):
448 ''' Subclass to write commit data into installation tree '''
427 ''' Subclass to write commit data into installation tree '''
449 def run(self):
428 def run(self):
450 build_cmd.run(self)
429 build_cmd.run(self)
451 # this one will only fire for build commands
430 # this one will only fire for build commands
452 if hasattr(self, 'build_lib'):
431 if hasattr(self, 'build_lib'):
453 self._record_commit(self.build_lib)
432 self._record_commit(self.build_lib)
454
433
455 def make_release_tree(self, base_dir, files):
434 def make_release_tree(self, base_dir, files):
456 # this one will fire for sdist
435 # this one will fire for sdist
457 build_cmd.make_release_tree(self, base_dir, files)
436 build_cmd.make_release_tree(self, base_dir, files)
458 self._record_commit(base_dir)
437 self._record_commit(base_dir)
459
438
460 def _record_commit(self, base_dir):
439 def _record_commit(self, base_dir):
461 import subprocess
440 import subprocess
462 proc = subprocess.Popen('git rev-parse --short HEAD',
441 proc = subprocess.Popen('git rev-parse --short HEAD',
463 stdout=subprocess.PIPE,
442 stdout=subprocess.PIPE,
464 stderr=subprocess.PIPE,
443 stderr=subprocess.PIPE,
465 shell=True)
444 shell=True)
466 repo_commit, _ = proc.communicate()
445 repo_commit, _ = proc.communicate()
467 repo_commit = repo_commit.strip().decode("ascii")
446 repo_commit = repo_commit.strip().decode("ascii")
468
447
469 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
448 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
470 if os.path.isfile(out_pth) and not repo_commit:
449 if os.path.isfile(out_pth) and not repo_commit:
471 # nothing to write, don't clobber
450 # nothing to write, don't clobber
472 return
451 return
473
452
474 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
453 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
475
454
476 # remove to avoid overwriting original via hard link
455 # remove to avoid overwriting original via hard link
477 try:
456 try:
478 os.remove(out_pth)
457 os.remove(out_pth)
479 except (IOError, OSError):
458 except (IOError, OSError):
480 pass
459 pass
481 with open(out_pth, 'w') as out_file:
460 with open(out_pth, 'w') as out_file:
482 out_file.writelines([
461 out_file.writelines([
483 '# GENERATED BY setup.py\n',
462 '# GENERATED BY setup.py\n',
484 'commit = u"%s"\n' % repo_commit,
463 'commit = u"%s"\n' % repo_commit,
485 ])
464 ])
486 return MyBuildPy
465 return MyBuildPy
487
466
General Comments 0
You need to be logged in to leave comments. Login now