##// END OF EJS Templates
Cleanup: Remove distutils...
farisachugthai -
Show More
@@ -1,407 +1,407 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
16 import re
17 import os
15 import os
16 import re
18 import sys
17 import sys
18 from glob import glob
19 from logging import log
19
20
20 from distutils import log
21 from setuptools import Command
21 from distutils.command.build_py import build_py
22 from setuptools.command.build_py import build_py
23 # TODO: Replacement for this?
22 from distutils.command.build_scripts import build_scripts
24 from distutils.command.build_scripts import build_scripts
23 from distutils.command.install import install
25 from setuptools.command.install import install
24 from distutils.command.install_scripts import install_scripts
26 from setuptools.command.install_scripts import install_scripts
25 from distutils.cmd import Command
26 from glob import glob
27
27
28 from setupext import install_data_ext
28 from setupext import install_data_ext
29
29
30 #-------------------------------------------------------------------------------
30 #-------------------------------------------------------------------------------
31 # Useful globals and utility functions
31 # Useful globals and utility functions
32 #-------------------------------------------------------------------------------
32 #-------------------------------------------------------------------------------
33
33
34 # A few handy globals
34 # A few handy globals
35 isfile = os.path.isfile
35 isfile = os.path.isfile
36 pjoin = os.path.join
36 pjoin = os.path.join
37 repo_root = os.path.dirname(os.path.abspath(__file__))
37 repo_root = os.path.dirname(os.path.abspath(__file__))
38
38
39 def execfile(fname, globs, locs=None):
39 def execfile(fname, globs, locs=None):
40 locs = locs or globs
40 locs = locs or globs
41 with open(fname) as f:
41 with open(fname) as f:
42 exec(compile(f.read(), fname, "exec"), globs, locs)
42 exec(compile(f.read(), fname, "exec"), globs, locs)
43
43
44 # A little utility we'll need below, since glob() does NOT allow you to do
44 # A little utility we'll need below, since glob() does NOT allow you to do
45 # exclusion on multiple endings!
45 # exclusion on multiple endings!
46 def file_doesnt_endwith(test,endings):
46 def file_doesnt_endwith(test,endings):
47 """Return true if test is a file and its name does NOT end with any
47 """Return true if test is a file and its name does NOT end with any
48 of the strings listed in endings."""
48 of the strings listed in endings."""
49 if not isfile(test):
49 if not isfile(test):
50 return False
50 return False
51 for e in endings:
51 for e in endings:
52 if test.endswith(e):
52 if test.endswith(e):
53 return False
53 return False
54 return True
54 return True
55
55
56 #---------------------------------------------------------------------------
56 #---------------------------------------------------------------------------
57 # Basic project information
57 # Basic project information
58 #---------------------------------------------------------------------------
58 #---------------------------------------------------------------------------
59
59
60 # release.py contains version, authors, license, url, keywords, etc.
60 # release.py contains version, authors, license, url, keywords, etc.
61 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
61 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
62
62
63 # Create a dict with the basic information
63 # Create a dict with the basic information
64 # This dict is eventually passed to setup after additional keys are added.
64 # This dict is eventually passed to setup after additional keys are added.
65 setup_args = dict(
65 setup_args = dict(
66 name = name,
66 name = name,
67 version = version,
67 version = version,
68 description = description,
68 description = description,
69 long_description = long_description,
69 long_description = long_description,
70 author = author,
70 author = author,
71 author_email = author_email,
71 author_email = author_email,
72 url = url,
72 url = url,
73 license = license,
73 license = license,
74 platforms = platforms,
74 platforms = platforms,
75 keywords = keywords,
75 keywords = keywords,
76 classifiers = classifiers,
76 classifiers = classifiers,
77 cmdclass = {'install_data': install_data_ext},
77 cmdclass = {'install_data': install_data_ext},
78 project_urls={
78 project_urls={
79 'Documentation': 'https://ipython.readthedocs.io/',
79 'Documentation': 'https://ipython.readthedocs.io/',
80 'Funding' : 'https://numfocus.org/',
80 'Funding' : 'https://numfocus.org/',
81 'Source' : 'https://github.com/ipython/ipython',
81 'Source' : 'https://github.com/ipython/ipython',
82 'Tracker' : 'https://github.com/ipython/ipython/issues',
82 'Tracker' : 'https://github.com/ipython/ipython/issues',
83 }
83 }
84 )
84 )
85
85
86
86
87 #---------------------------------------------------------------------------
87 #---------------------------------------------------------------------------
88 # Find packages
88 # Find packages
89 #---------------------------------------------------------------------------
89 #---------------------------------------------------------------------------
90
90
91 def find_packages():
91 def find_packages():
92 """
92 """
93 Find all of IPython's packages.
93 Find all of IPython's packages.
94 """
94 """
95 excludes = ['deathrow', 'quarantine']
95 excludes = ['deathrow', 'quarantine']
96 packages = []
96 packages = []
97 for dir,subdirs,files in os.walk('IPython'):
97 for dir,subdirs,files in os.walk('IPython'):
98 package = dir.replace(os.path.sep, '.')
98 package = dir.replace(os.path.sep, '.')
99 if any(package.startswith('IPython.'+exc) for exc in excludes):
99 if any(package.startswith('IPython.'+exc) for exc in excludes):
100 # package is to be excluded (e.g. deathrow)
100 # package is to be excluded (e.g. deathrow)
101 continue
101 continue
102 if '__init__.py' not in files:
102 if '__init__.py' not in files:
103 # not a package
103 # not a package
104 continue
104 continue
105 packages.append(package)
105 packages.append(package)
106 return packages
106 return packages
107
107
108 #---------------------------------------------------------------------------
108 #---------------------------------------------------------------------------
109 # Find package data
109 # Find package data
110 #---------------------------------------------------------------------------
110 #---------------------------------------------------------------------------
111
111
112 def find_package_data():
112 def find_package_data():
113 """
113 """
114 Find IPython's package_data.
114 Find IPython's package_data.
115 """
115 """
116 # This is not enough for these things to appear in an sdist.
116 # This is not enough for these things to appear in an sdist.
117 # We need to muck with the MANIFEST to get this to work
117 # We need to muck with the MANIFEST to get this to work
118
118
119 package_data = {
119 package_data = {
120 'IPython.core' : ['profile/README*'],
120 'IPython.core' : ['profile/README*'],
121 'IPython.core.tests' : ['*.png', '*.jpg', 'daft_extension/*.py'],
121 'IPython.core.tests' : ['*.png', '*.jpg', 'daft_extension/*.py'],
122 'IPython.lib.tests' : ['*.wav'],
122 'IPython.lib.tests' : ['*.wav'],
123 'IPython.testing.plugin' : ['*.txt'],
123 'IPython.testing.plugin' : ['*.txt'],
124 }
124 }
125
125
126 return package_data
126 return package_data
127
127
128
128
129 def check_package_data(package_data):
129 def check_package_data(package_data):
130 """verify that package_data globs make sense"""
130 """verify that package_data globs make sense"""
131 print("checking package data")
131 print("checking package data")
132 for pkg, data in package_data.items():
132 for pkg, data in package_data.items():
133 pkg_root = pjoin(*pkg.split('.'))
133 pkg_root = pjoin(*pkg.split('.'))
134 for d in data:
134 for d in data:
135 path = pjoin(pkg_root, d)
135 path = pjoin(pkg_root, d)
136 if '*' in path:
136 if '*' in path:
137 assert len(glob(path)) > 0, "No files match pattern %s" % path
137 assert len(glob(path)) > 0, "No files match pattern %s" % path
138 else:
138 else:
139 assert os.path.exists(path), "Missing package data: %s" % path
139 assert os.path.exists(path), "Missing package data: %s" % path
140
140
141
141
142 def check_package_data_first(command):
142 def check_package_data_first(command):
143 """decorator for checking package_data before running a given command
143 """decorator for checking package_data before running a given command
144
144
145 Probably only needs to wrap build_py
145 Probably only needs to wrap build_py
146 """
146 """
147 class DecoratedCommand(command):
147 class DecoratedCommand(command):
148 def run(self):
148 def run(self):
149 check_package_data(self.package_data)
149 check_package_data(self.package_data)
150 command.run(self)
150 command.run(self)
151 return DecoratedCommand
151 return DecoratedCommand
152
152
153
153
154 #---------------------------------------------------------------------------
154 #---------------------------------------------------------------------------
155 # Find data files
155 # Find data files
156 #---------------------------------------------------------------------------
156 #---------------------------------------------------------------------------
157
157
158 def find_data_files():
158 def find_data_files():
159 """
159 """
160 Find IPython's data_files.
160 Find IPython's data_files.
161
161
162 Just man pages at this point.
162 Just man pages at this point.
163 """
163 """
164
164
165 if "freebsd" in sys.platform:
165 if "freebsd" in sys.platform:
166 manpagebase = pjoin('man', 'man1')
166 manpagebase = pjoin('man', 'man1')
167 else:
167 else:
168 manpagebase = pjoin('share', 'man', 'man1')
168 manpagebase = pjoin('share', 'man', 'man1')
169
169
170 # Simple file lists can be made by hand
170 # Simple file lists can be made by hand
171 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
171 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
172 if not manpages:
172 if not manpages:
173 # When running from a source tree, the manpages aren't gzipped
173 # When running from a source tree, the manpages aren't gzipped
174 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
174 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
175
175
176 # And assemble the entire output list
176 # And assemble the entire output list
177 data_files = [ (manpagebase, manpages) ]
177 data_files = [ (manpagebase, manpages) ]
178
178
179 return data_files
179 return data_files
180
180
181
181
182 # The two functions below are copied from IPython.utils.path, so we don't need
182 # The two functions below are copied from IPython.utils.path, so we don't need
183 # to import IPython during setup, which fails on Python 3.
183 # to import IPython during setup, which fails on Python 3.
184
184
185 def target_outdated(target,deps):
185 def target_outdated(target,deps):
186 """Determine whether a target is out of date.
186 """Determine whether a target is out of date.
187
187
188 target_outdated(target,deps) -> 1/0
188 target_outdated(target,deps) -> 1/0
189
189
190 deps: list of filenames which MUST exist.
190 deps: list of filenames which MUST exist.
191 target: single filename which may or may not exist.
191 target: single filename which may or may not exist.
192
192
193 If target doesn't exist or is older than any file listed in deps, return
193 If target doesn't exist or is older than any file listed in deps, return
194 true, otherwise return false.
194 true, otherwise return false.
195 """
195 """
196 try:
196 try:
197 target_time = os.path.getmtime(target)
197 target_time = os.path.getmtime(target)
198 except os.error:
198 except os.error:
199 return 1
199 return 1
200 for dep in deps:
200 for dep in deps:
201 dep_time = os.path.getmtime(dep)
201 dep_time = os.path.getmtime(dep)
202 if dep_time > target_time:
202 if dep_time > target_time:
203 #print "For target",target,"Dep failed:",dep # dbg
203 #print "For target",target,"Dep failed:",dep # dbg
204 #print "times (dep,tar):",dep_time,target_time # dbg
204 #print "times (dep,tar):",dep_time,target_time # dbg
205 return 1
205 return 1
206 return 0
206 return 0
207
207
208
208
209 def target_update(target,deps,cmd):
209 def target_update(target,deps,cmd):
210 """Update a target with a given command given a list of dependencies.
210 """Update a target with a given command given a list of dependencies.
211
211
212 target_update(target,deps,cmd) -> runs cmd if target is outdated.
212 target_update(target,deps,cmd) -> runs cmd if target is outdated.
213
213
214 This is just a wrapper around target_outdated() which calls the given
214 This is just a wrapper around target_outdated() which calls the given
215 command if target is outdated."""
215 command if target is outdated."""
216
216
217 if target_outdated(target,deps):
217 if target_outdated(target,deps):
218 os.system(cmd)
218 os.system(cmd)
219
219
220 #---------------------------------------------------------------------------
220 #---------------------------------------------------------------------------
221 # Find scripts
221 # Find scripts
222 #---------------------------------------------------------------------------
222 #---------------------------------------------------------------------------
223
223
224 def find_entry_points():
224 def find_entry_points():
225 """Defines the command line entry points for IPython
225 """Defines the command line entry points for IPython
226
226
227 This always uses setuptools-style entry points. When setuptools is not in
227 This always uses setuptools-style entry points. When setuptools is not in
228 use, our own build_scripts_entrypt class below parses these and builds
228 use, our own build_scripts_entrypt class below parses these and builds
229 command line scripts.
229 command line scripts.
230
230
231 Each of our entry points gets both a plain name, e.g. ipython, and one
231 Each of our entry points gets both a plain name, e.g. ipython, and one
232 suffixed with the Python major version number, e.g. ipython3.
232 suffixed with the Python major version number, e.g. ipython3.
233 """
233 """
234 ep = [
234 ep = [
235 'ipython%s = IPython:start_ipython',
235 'ipython%s = IPython:start_ipython',
236 'iptest%s = IPython.testing.iptestcontroller:main',
236 'iptest%s = IPython.testing.iptestcontroller:main',
237 ]
237 ]
238 suffix = str(sys.version_info[0])
238 suffix = str(sys.version_info[0])
239 return [e % '' for e in ep] + [e % suffix for e in ep]
239 return [e % '' for e in ep] + [e % suffix for e in ep]
240
240
241 script_src = """#!{executable}
241 script_src = """#!{executable}
242 # This script was automatically generated by setup.py
242 # This script was automatically generated by setup.py
243 if __name__ == '__main__':
243 if __name__ == '__main__':
244 from {mod} import {func}
244 from {mod} import {func}
245 {func}()
245 {func}()
246 """
246 """
247
247
248 class build_scripts_entrypt(build_scripts):
248 class build_scripts_entrypt(build_scripts):
249 """Build the command line scripts
249 """Build the command line scripts
250
250
251 Parse setuptools style entry points and write simple scripts to run the
251 Parse setuptools style entry points and write simple scripts to run the
252 target functions.
252 target functions.
253
253
254 On Windows, this also creates .cmd wrappers for the scripts so that you can
254 On Windows, this also creates .cmd wrappers for the scripts so that you can
255 easily launch them from a command line.
255 easily launch them from a command line.
256 """
256 """
257 def run(self):
257 def run(self):
258 self.mkpath(self.build_dir)
258 self.mkpath(self.build_dir)
259 outfiles = []
259 outfiles = []
260 for script in find_entry_points():
260 for script in find_entry_points():
261 name, entrypt = script.split('=')
261 name, entrypt = script.split('=')
262 name = name.strip()
262 name = name.strip()
263 entrypt = entrypt.strip()
263 entrypt = entrypt.strip()
264 outfile = os.path.join(self.build_dir, name)
264 outfile = os.path.join(self.build_dir, name)
265 outfiles.append(outfile)
265 outfiles.append(outfile)
266 print('Writing script to', outfile)
266 print('Writing script to', outfile)
267
267
268 mod, func = entrypt.split(':')
268 mod, func = entrypt.split(':')
269 with open(outfile, 'w') as f:
269 with open(outfile, 'w') as f:
270 f.write(script_src.format(executable=sys.executable,
270 f.write(script_src.format(executable=sys.executable,
271 mod=mod, func=func))
271 mod=mod, func=func))
272
272
273 if sys.platform == 'win32':
273 if sys.platform == 'win32':
274 # Write .cmd wrappers for Windows so 'ipython' etc. work at the
274 # Write .cmd wrappers for Windows so 'ipython' etc. work at the
275 # command line
275 # command line
276 cmd_file = os.path.join(self.build_dir, name + '.cmd')
276 cmd_file = os.path.join(self.build_dir, name + '.cmd')
277 cmd = r'@"{python}" "%~dp0\{script}" %*\r\n'.format(
277 cmd = r'@"{python}" "%~dp0\{script}" %*\r\n'.format(
278 python=sys.executable, script=name)
278 python=sys.executable, script=name)
279 log.info("Writing %s wrapper script" % cmd_file)
279 log.info("Writing %s wrapper script" % cmd_file)
280 with open(cmd_file, 'w') as f:
280 with open(cmd_file, 'w') as f:
281 f.write(cmd)
281 f.write(cmd)
282
282
283 return outfiles, outfiles
283 return outfiles, outfiles
284
284
285 class install_lib_symlink(Command):
285 class install_lib_symlink(Command):
286 user_options = [
286 user_options = [
287 ('install-dir=', 'd', "directory to install to"),
287 ('install-dir=', 'd', "directory to install to"),
288 ]
288 ]
289
289
290 def initialize_options(self):
290 def initialize_options(self):
291 self.install_dir = None
291 self.install_dir = None
292
292
293 def finalize_options(self):
293 def finalize_options(self):
294 self.set_undefined_options('symlink',
294 self.set_undefined_options('symlink',
295 ('install_lib', 'install_dir'),
295 ('install_lib', 'install_dir'),
296 )
296 )
297
297
298 def run(self):
298 def run(self):
299 if sys.platform == 'win32':
299 if sys.platform == 'win32':
300 raise Exception("This doesn't work on Windows.")
300 raise Exception("This doesn't work on Windows.")
301 pkg = os.path.join(os.getcwd(), 'IPython')
301 pkg = os.path.join(os.getcwd(), 'IPython')
302 dest = os.path.join(self.install_dir, 'IPython')
302 dest = os.path.join(self.install_dir, 'IPython')
303 if os.path.islink(dest):
303 if os.path.islink(dest):
304 print('removing existing symlink at %s' % dest)
304 print('removing existing symlink at %s' % dest)
305 os.unlink(dest)
305 os.unlink(dest)
306 print('symlinking %s -> %s' % (pkg, dest))
306 print('symlinking %s -> %s' % (pkg, dest))
307 os.symlink(pkg, dest)
307 os.symlink(pkg, dest)
308
308
309 class unsymlink(install):
309 class unsymlink(install):
310 def run(self):
310 def run(self):
311 dest = os.path.join(self.install_lib, 'IPython')
311 dest = os.path.join(self.install_lib, 'IPython')
312 if os.path.islink(dest):
312 if os.path.islink(dest):
313 print('removing symlink at %s' % dest)
313 print('removing symlink at %s' % dest)
314 os.unlink(dest)
314 os.unlink(dest)
315 else:
315 else:
316 print('No symlink exists at %s' % dest)
316 print('No symlink exists at %s' % dest)
317
317
318 class install_symlinked(install):
318 class install_symlinked(install):
319 def run(self):
319 def run(self):
320 if sys.platform == 'win32':
320 if sys.platform == 'win32':
321 raise Exception("This doesn't work on Windows.")
321 raise Exception("This doesn't work on Windows.")
322
322
323 # Run all sub-commands (at least those that need to be run)
323 # Run all sub-commands (at least those that need to be run)
324 for cmd_name in self.get_sub_commands():
324 for cmd_name in self.get_sub_commands():
325 self.run_command(cmd_name)
325 self.run_command(cmd_name)
326
326
327 # 'sub_commands': a list of commands this command might have to run to
327 # 'sub_commands': a list of commands this command might have to run to
328 # get its work done. See cmd.py for more info.
328 # get its work done. See cmd.py for more info.
329 sub_commands = [('install_lib_symlink', lambda self:True),
329 sub_commands = [('install_lib_symlink', lambda self:True),
330 ('install_scripts_sym', lambda self:True),
330 ('install_scripts_sym', lambda self:True),
331 ]
331 ]
332
332
333 class install_scripts_for_symlink(install_scripts):
333 class install_scripts_for_symlink(install_scripts):
334 """Redefined to get options from 'symlink' instead of 'install'.
334 """Redefined to get options from 'symlink' instead of 'install'.
335
335
336 I love distutils almost as much as I love setuptools.
336 I love distutils almost as much as I love setuptools.
337 """
337 """
338 def finalize_options(self):
338 def finalize_options(self):
339 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
339 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
340 self.set_undefined_options('symlink',
340 self.set_undefined_options('symlink',
341 ('install_scripts', 'install_dir'),
341 ('install_scripts', 'install_dir'),
342 ('force', 'force'),
342 ('force', 'force'),
343 ('skip_build', 'skip_build'),
343 ('skip_build', 'skip_build'),
344 )
344 )
345
345
346
346
347 #---------------------------------------------------------------------------
347 #---------------------------------------------------------------------------
348 # VCS related
348 # VCS related
349 #---------------------------------------------------------------------------
349 #---------------------------------------------------------------------------
350
350
351
351
352 def git_prebuild(pkg_dir, build_cmd=build_py):
352 def git_prebuild(pkg_dir, build_cmd=build_py):
353 """Return extended build or sdist command class for recording commit
353 """Return extended build or sdist command class for recording commit
354
354
355 records git commit in IPython.utils._sysinfo.commit
355 records git commit in IPython.utils._sysinfo.commit
356
356
357 for use in IPython.utils.sysinfo.sys_info() calls after installation.
357 for use in IPython.utils.sysinfo.sys_info() calls after installation.
358 """
358 """
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 # loose as `.dev` is suppose to be invalid
363 # loose as `.dev` is suppose to be invalid
364 print("check version number")
364 print("check version number")
365 loose_pep440re = re.compile(r'^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$')
365 loose_pep440re = re.compile(r'^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$')
366 if not loose_pep440re.match(version):
366 if not loose_pep440re.match(version):
367 raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % version)
367 raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % version)
368
368
369
369
370 build_cmd.run(self)
370 build_cmd.run(self)
371 # this one will only fire for build commands
371 # this one will only fire for build commands
372 if hasattr(self, 'build_lib'):
372 if hasattr(self, 'build_lib'):
373 self._record_commit(self.build_lib)
373 self._record_commit(self.build_lib)
374
374
375 def make_release_tree(self, base_dir, files):
375 def make_release_tree(self, base_dir, files):
376 # this one will fire for sdist
376 # this one will fire for sdist
377 build_cmd.make_release_tree(self, base_dir, files)
377 build_cmd.make_release_tree(self, base_dir, files)
378 self._record_commit(base_dir)
378 self._record_commit(base_dir)
379
379
380 def _record_commit(self, base_dir):
380 def _record_commit(self, base_dir):
381 import subprocess
381 import subprocess
382 proc = subprocess.Popen('git rev-parse --short HEAD',
382 proc = subprocess.Popen('git rev-parse --short HEAD',
383 stdout=subprocess.PIPE,
383 stdout=subprocess.PIPE,
384 stderr=subprocess.PIPE,
384 stderr=subprocess.PIPE,
385 shell=True)
385 shell=True)
386 repo_commit, _ = proc.communicate()
386 repo_commit, _ = proc.communicate()
387 repo_commit = repo_commit.strip().decode("ascii")
387 repo_commit = repo_commit.strip().decode("ascii")
388
388
389 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
389 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
390 if os.path.isfile(out_pth) and not repo_commit:
390 if os.path.isfile(out_pth) and not repo_commit:
391 # nothing to write, don't clobber
391 # nothing to write, don't clobber
392 return
392 return
393
393
394 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
394 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
395
395
396 # remove to avoid overwriting original via hard link
396 # remove to avoid overwriting original via hard link
397 try:
397 try:
398 os.remove(out_pth)
398 os.remove(out_pth)
399 except (IOError, OSError):
399 except (IOError, OSError):
400 pass
400 pass
401 with open(out_pth, 'w') as out_file:
401 with open(out_pth, 'w') as out_file:
402 out_file.writelines([
402 out_file.writelines([
403 '# GENERATED BY setup.py\n',
403 '# GENERATED BY setup.py\n',
404 'commit = u"%s"\n' % repo_commit,
404 'commit = u"%s"\n' % repo_commit,
405 ])
405 ])
406 return MyBuildPy
406 return MyBuildPy
407
407
General Comments 0
You need to be logged in to leave comments. Login now