##// END OF EJS Templates
store git commit hash in utils._sysinfo instead of hidden git_commit_info.ini data file.
MinRK -
Show More
@@ -0,0 +1,2 b''
1 # GENERATED BY setup.py
2 commit = ''
@@ -1,191 +1,167 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for getting information about IPython and the system it's running in.
3 Utilities for getting information about IPython and the system it's running in.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import os
17 import os
18 import platform
18 import platform
19 import pprint
19 import pprint
20 import sys
20 import sys
21 import subprocess
21 import subprocess
22
22
23 from ConfigParser import ConfigParser
23 from ConfigParser import ConfigParser
24
24
25 from IPython.core import release
25 from IPython.core import release
26 from IPython.utils import py3compat
26 from IPython.utils import py3compat, _sysinfo
27
28 #-----------------------------------------------------------------------------
29 # Globals
30 #-----------------------------------------------------------------------------
31 COMMIT_INFO_FNAME = '.git_commit_info.ini'
32
27
33 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
34 # Code
29 # Code
35 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
36
31
37 def pkg_commit_hash(pkg_path):
32 def pkg_commit_hash(pkg_path):
38 """Get short form of commit hash given directory `pkg_path`
33 """Get short form of commit hash given directory `pkg_path`
39
34
40 There should be a file called 'COMMIT_INFO.txt' in `pkg_path`. This is a
41 file in INI file format, with at least one section: ``commit hash``, and two
42 variables ``archive_subst_hash`` and ``install_hash``. The first has a
43 substitution pattern in it which may have been filled by the execution of
44 ``git archive`` if this is an archive generated that way. The second is
45 filled in by the installation, if the installation is from a git archive.
46
47 We get the commit hash from (in order of preference):
35 We get the commit hash from (in order of preference):
48
36
49 * A substituted value in ``archive_subst_hash``
37 * IPython.utils._sysinfo.commit
50 * A written commit hash value in ``install_hash`
51 * git output, if we are in a git repository
38 * git output, if we are in a git repository
52
39
53 If all these fail, we return a not-found placeholder tuple
40 If these fail, we return a not-found placeholder tuple
54
41
55 Parameters
42 Parameters
56 ----------
43 ----------
57 pkg_path : str
44 pkg_path : str
58 directory containing package
45 directory containing package
46 only used for getting commit from active repo
59
47
60 Returns
48 Returns
61 -------
49 -------
62 hash_from : str
50 hash_from : str
63 Where we got the hash from - description
51 Where we got the hash from - description
64 hash_str : str
52 hash_str : str
65 short form of hash
53 short form of hash
66 """
54 """
67 # Try and get commit from written commit text file
55 # Try and get commit from written commit text file
68 pth = os.path.join(pkg_path, COMMIT_INFO_FNAME)
56 if _sysinfo.commit:
69 if not os.path.isfile(pth):
57 return "installation", _sysinfo.commit
70 raise IOError('Missing commit info file %s' % pth)
58
71 cfg_parser = ConfigParser()
72 cfg_parser.read(pth)
73 try:
74 archive_subst = cfg_parser.get('commit hash', 'archive_subst_hash')
75 except Exception:
76 pass
77 else:
78 if not archive_subst.startswith('$Format'): # it has been substituted
79 return 'archive substitution', archive_subst
80 install_subst = cfg_parser.get('commit hash', 'install_hash')
81 if install_subst != '':
82 return 'installation', install_subst
83 # maybe we are in a repository
59 # maybe we are in a repository
84 proc = subprocess.Popen('git rev-parse --short HEAD',
60 proc = subprocess.Popen('git rev-parse --short HEAD',
85 stdout=subprocess.PIPE,
61 stdout=subprocess.PIPE,
86 stderr=subprocess.PIPE,
62 stderr=subprocess.PIPE,
87 cwd=pkg_path, shell=True)
63 cwd=pkg_path, shell=True)
88 repo_commit, _ = proc.communicate()
64 repo_commit, _ = proc.communicate()
89 if repo_commit:
65 if repo_commit:
90 return 'repository', repo_commit.strip()
66 return 'repository', repo_commit.strip()
91 return '(none found)', '<not found>'
67 return '(none found)', '<not found>'
92
68
93
69
94 def pkg_info(pkg_path):
70 def pkg_info(pkg_path):
95 """Return dict describing the context of this package
71 """Return dict describing the context of this package
96
72
97 Parameters
73 Parameters
98 ----------
74 ----------
99 pkg_path : str
75 pkg_path : str
100 path containing __init__.py for package
76 path containing __init__.py for package
101
77
102 Returns
78 Returns
103 -------
79 -------
104 context : dict
80 context : dict
105 with named parameters of interest
81 with named parameters of interest
106 """
82 """
107 src, hsh = pkg_commit_hash(pkg_path)
83 src, hsh = pkg_commit_hash(pkg_path)
108 return dict(
84 return dict(
109 ipython_version=release.version,
85 ipython_version=release.version,
110 ipython_path=pkg_path,
86 ipython_path=pkg_path,
111 commit_source=src,
87 commit_source=src,
112 commit_hash=hsh,
88 commit_hash=hsh,
113 sys_version=sys.version,
89 sys_version=sys.version,
114 sys_executable=sys.executable,
90 sys_executable=sys.executable,
115 sys_platform=sys.platform,
91 sys_platform=sys.platform,
116 platform=platform.platform(),
92 platform=platform.platform(),
117 os_name=os.name,
93 os_name=os.name,
118 )
94 )
119
95
120
96
121 @py3compat.doctest_refactor_print
97 @py3compat.doctest_refactor_print
122 def sys_info():
98 def sys_info():
123 """Return useful information about IPython and the system, as a string.
99 """Return useful information about IPython and the system, as a string.
124
100
125 Example
101 Example
126 -------
102 -------
127 In [2]: print sys_info()
103 In [2]: print sys_info()
128 {'commit_hash': '144fdae', # random
104 {'commit_hash': '144fdae', # random
129 'commit_source': 'repository',
105 'commit_source': 'repository',
130 'ipython_path': '/home/fperez/usr/lib/python2.6/site-packages/IPython',
106 'ipython_path': '/home/fperez/usr/lib/python2.6/site-packages/IPython',
131 'ipython_version': '0.11.dev',
107 'ipython_version': '0.11.dev',
132 'os_name': 'posix',
108 'os_name': 'posix',
133 'platform': 'Linux-2.6.35-22-generic-i686-with-Ubuntu-10.10-maverick',
109 'platform': 'Linux-2.6.35-22-generic-i686-with-Ubuntu-10.10-maverick',
134 'sys_executable': '/usr/bin/python',
110 'sys_executable': '/usr/bin/python',
135 'sys_platform': 'linux2',
111 'sys_platform': 'linux2',
136 'sys_version': '2.6.6 (r266:84292, Sep 15 2010, 15:52:39) \\n[GCC 4.4.5]'}
112 'sys_version': '2.6.6 (r266:84292, Sep 15 2010, 15:52:39) \\n[GCC 4.4.5]'}
137 """
113 """
138 p = os.path
114 p = os.path
139 path = p.dirname(p.abspath(p.join(__file__, '..')))
115 path = p.dirname(p.abspath(p.join(__file__, '..')))
140 return pprint.pformat(pkg_info(path))
116 return pprint.pformat(pkg_info(path))
141
117
142
118
143 def _num_cpus_unix():
119 def _num_cpus_unix():
144 """Return the number of active CPUs on a Unix system."""
120 """Return the number of active CPUs on a Unix system."""
145 return os.sysconf("SC_NPROCESSORS_ONLN")
121 return os.sysconf("SC_NPROCESSORS_ONLN")
146
122
147
123
148 def _num_cpus_darwin():
124 def _num_cpus_darwin():
149 """Return the number of active CPUs on a Darwin system."""
125 """Return the number of active CPUs on a Darwin system."""
150 p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
126 p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
151 return p.stdout.read()
127 return p.stdout.read()
152
128
153
129
154 def _num_cpus_windows():
130 def _num_cpus_windows():
155 """Return the number of active CPUs on a Windows system."""
131 """Return the number of active CPUs on a Windows system."""
156 return os.environ.get("NUMBER_OF_PROCESSORS")
132 return os.environ.get("NUMBER_OF_PROCESSORS")
157
133
158
134
159 def num_cpus():
135 def num_cpus():
160 """Return the effective number of CPUs in the system as an integer.
136 """Return the effective number of CPUs in the system as an integer.
161
137
162 This cross-platform function makes an attempt at finding the total number of
138 This cross-platform function makes an attempt at finding the total number of
163 available CPUs in the system, as returned by various underlying system and
139 available CPUs in the system, as returned by various underlying system and
164 python calls.
140 python calls.
165
141
166 If it can't find a sensible answer, it returns 1 (though an error *may* make
142 If it can't find a sensible answer, it returns 1 (though an error *may* make
167 it return a large positive number that's actually incorrect).
143 it return a large positive number that's actually incorrect).
168 """
144 """
169
145
170 # Many thanks to the Parallel Python project (http://www.parallelpython.com)
146 # Many thanks to the Parallel Python project (http://www.parallelpython.com)
171 # for the names of the keys we needed to look up for this function. This
147 # for the names of the keys we needed to look up for this function. This
172 # code was inspired by their equivalent function.
148 # code was inspired by their equivalent function.
173
149
174 ncpufuncs = {'Linux':_num_cpus_unix,
150 ncpufuncs = {'Linux':_num_cpus_unix,
175 'Darwin':_num_cpus_darwin,
151 'Darwin':_num_cpus_darwin,
176 'Windows':_num_cpus_windows,
152 'Windows':_num_cpus_windows,
177 # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
153 # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
178 # See http://bugs.python.org/issue1082 for details.
154 # See http://bugs.python.org/issue1082 for details.
179 'Microsoft':_num_cpus_windows,
155 'Microsoft':_num_cpus_windows,
180 }
156 }
181
157
182 ncpufunc = ncpufuncs.get(platform.system(),
158 ncpufunc = ncpufuncs.get(platform.system(),
183 # default to unix version (Solaris, AIX, etc)
159 # default to unix version (Solaris, AIX, etc)
184 _num_cpus_unix)
160 _num_cpus_unix)
185
161
186 try:
162 try:
187 ncpus = max(1,int(ncpufunc()))
163 ncpus = max(1,int(ncpufunc()))
188 except:
164 except:
189 ncpus = 1
165 ncpus = 1
190 return ncpus
166 return ncpus
191
167
@@ -1,428 +1,397 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 io
23 import os
24 import os
24 import sys
25 import sys
25
26
26 try:
27 try:
27 from configparser import ConfigParser
28 from configparser import ConfigParser
28 except:
29 except:
29 from ConfigParser import ConfigParser
30 from ConfigParser import ConfigParser
30 from distutils.command.build_py import build_py
31 from distutils.command.build_py import build_py
31 from glob import glob
32 from glob import glob
32
33
33 from setupext import install_data_ext
34 from setupext import install_data_ext
34
35
35 #-------------------------------------------------------------------------------
36 #-------------------------------------------------------------------------------
36 # Useful globals and utility functions
37 # Useful globals and utility functions
37 #-------------------------------------------------------------------------------
38 #-------------------------------------------------------------------------------
38
39
39 # A few handy globals
40 # A few handy globals
40 isfile = os.path.isfile
41 isfile = os.path.isfile
41 pjoin = os.path.join
42 pjoin = os.path.join
42
43
43 def oscmd(s):
44 def oscmd(s):
44 print(">", s)
45 print(">", s)
45 os.system(s)
46 os.system(s)
46
47
47 try:
48 try:
48 execfile
49 execfile
49 except NameError:
50 except NameError:
50 def execfile(fname, globs, locs=None):
51 def execfile(fname, globs, locs=None):
51 locs = locs or globs
52 locs = locs or globs
52 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
53 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
53
54
54 # A little utility we'll need below, since glob() does NOT allow you to do
55 # A little utility we'll need below, since glob() does NOT allow you to do
55 # exclusion on multiple endings!
56 # exclusion on multiple endings!
56 def file_doesnt_endwith(test,endings):
57 def file_doesnt_endwith(test,endings):
57 """Return true if test is a file and its name does NOT end with any
58 """Return true if test is a file and its name does NOT end with any
58 of the strings listed in endings."""
59 of the strings listed in endings."""
59 if not isfile(test):
60 if not isfile(test):
60 return False
61 return False
61 for e in endings:
62 for e in endings:
62 if test.endswith(e):
63 if test.endswith(e):
63 return False
64 return False
64 return True
65 return True
65
66
66 #---------------------------------------------------------------------------
67 #---------------------------------------------------------------------------
67 # Basic project information
68 # Basic project information
68 #---------------------------------------------------------------------------
69 #---------------------------------------------------------------------------
69
70
70 # release.py contains version, authors, license, url, keywords, etc.
71 # release.py contains version, authors, license, url, keywords, etc.
71 execfile(pjoin('IPython','core','release.py'), globals())
72 execfile(pjoin('IPython','core','release.py'), globals())
72
73
73 # Create a dict with the basic information
74 # Create a dict with the basic information
74 # This dict is eventually passed to setup after additional keys are added.
75 # This dict is eventually passed to setup after additional keys are added.
75 setup_args = dict(
76 setup_args = dict(
76 name = name,
77 name = name,
77 version = version,
78 version = version,
78 description = description,
79 description = description,
79 long_description = long_description,
80 long_description = long_description,
80 author = author,
81 author = author,
81 author_email = author_email,
82 author_email = author_email,
82 url = url,
83 url = url,
83 download_url = download_url,
84 download_url = download_url,
84 license = license,
85 license = license,
85 platforms = platforms,
86 platforms = platforms,
86 keywords = keywords,
87 keywords = keywords,
87 classifiers = classifiers,
88 classifiers = classifiers,
88 cmdclass = {'install_data': install_data_ext},
89 cmdclass = {'install_data': install_data_ext},
89 )
90 )
90
91
91
92
92 #---------------------------------------------------------------------------
93 #---------------------------------------------------------------------------
93 # Find packages
94 # Find packages
94 #---------------------------------------------------------------------------
95 #---------------------------------------------------------------------------
95
96
96 def find_packages():
97 def find_packages():
97 """
98 """
98 Find all of IPython's packages.
99 Find all of IPython's packages.
99 """
100 """
100 excludes = ['deathrow']
101 excludes = ['deathrow']
101 packages = []
102 packages = []
102 for dir,subdirs,files in os.walk('IPython'):
103 for dir,subdirs,files in os.walk('IPython'):
103 package = dir.replace(os.path.sep, '.')
104 package = dir.replace(os.path.sep, '.')
104 if any([ package.startswith('IPython.'+exc) for exc in excludes ]):
105 if any([ package.startswith('IPython.'+exc) for exc in excludes ]):
105 # package is to be excluded (e.g. deathrow)
106 # package is to be excluded (e.g. deathrow)
106 continue
107 continue
107 if '__init__.py' not in files:
108 if '__init__.py' not in files:
108 # not a package
109 # not a package
109 continue
110 continue
110 packages.append(package)
111 packages.append(package)
111 return packages
112 return packages
112
113
113 #---------------------------------------------------------------------------
114 #---------------------------------------------------------------------------
114 # Find package data
115 # Find package data
115 #---------------------------------------------------------------------------
116 #---------------------------------------------------------------------------
116
117
117 def find_package_data():
118 def find_package_data():
118 """
119 """
119 Find IPython's package_data.
120 Find IPython's package_data.
120 """
121 """
121 # This is not enough for these things to appear in an sdist.
122 # 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
123 # We need to muck with the MANIFEST to get this to work
123
124
124 # exclude static things that we don't ship (e.g. mathjax)
125 # exclude static things that we don't ship (e.g. mathjax)
125 excludes = ['mathjax']
126 excludes = ['mathjax']
126
127
127 # add 'static/' prefix to exclusions, and tuplify for use in startswith
128 # add 'static/' prefix to exclusions, and tuplify for use in startswith
128 excludes = tuple([os.path.join('static', ex) for ex in excludes])
129 excludes = tuple([os.path.join('static', ex) for ex in excludes])
129
130
130 # walk notebook resources:
131 # walk notebook resources:
131 cwd = os.getcwd()
132 cwd = os.getcwd()
132 os.chdir(os.path.join('IPython', 'frontend', 'html', 'notebook'))
133 os.chdir(os.path.join('IPython', 'frontend', 'html', 'notebook'))
133 static_walk = list(os.walk('static'))
134 static_walk = list(os.walk('static'))
134 os.chdir(cwd)
135 os.chdir(cwd)
135 static_data = []
136 static_data = []
136 for parent, dirs, files in static_walk:
137 for parent, dirs, files in static_walk:
137 if parent.startswith(excludes):
138 if parent.startswith(excludes):
138 continue
139 continue
139 for f in files:
140 for f in files:
140 static_data.append(os.path.join(parent, f))
141 static_data.append(os.path.join(parent, f))
141
142
142 package_data = {
143 package_data = {
143 'IPython.config.profile' : ['README*', '*/*.py'],
144 'IPython.config.profile' : ['README*', '*/*.py'],
144 'IPython.testing' : ['*.txt'],
145 'IPython.testing' : ['*.txt'],
145 'IPython.frontend.html.notebook' : ['templates/*'] + static_data,
146 'IPython.frontend.html.notebook' : ['templates/*'] + static_data,
146 'IPython.frontend.qt.console' : ['resources/icon/*.svg'],
147 'IPython.frontend.qt.console' : ['resources/icon/*.svg'],
147 }
148 }
148 return package_data
149 return package_data
149
150
150
151
151 #---------------------------------------------------------------------------
152 #---------------------------------------------------------------------------
152 # Find data files
153 # Find data files
153 #---------------------------------------------------------------------------
154 #---------------------------------------------------------------------------
154
155
155 def make_dir_struct(tag,base,out_base):
156 def make_dir_struct(tag,base,out_base):
156 """Make the directory structure of all files below a starting dir.
157 """Make the directory structure of all files below a starting dir.
157
158
158 This is just a convenience routine to help build a nested directory
159 This is just a convenience routine to help build a nested directory
159 hierarchy because distutils is too stupid to do this by itself.
160 hierarchy because distutils is too stupid to do this by itself.
160
161
161 XXX - this needs a proper docstring!
162 XXX - this needs a proper docstring!
162 """
163 """
163
164
164 # we'll use these a lot below
165 # we'll use these a lot below
165 lbase = len(base)
166 lbase = len(base)
166 pathsep = os.path.sep
167 pathsep = os.path.sep
167 lpathsep = len(pathsep)
168 lpathsep = len(pathsep)
168
169
169 out = []
170 out = []
170 for (dirpath,dirnames,filenames) in os.walk(base):
171 for (dirpath,dirnames,filenames) in os.walk(base):
171 # we need to strip out the dirpath from the base to map it to the
172 # we need to strip out the dirpath from the base to map it to the
172 # output (installation) path. This requires possibly stripping the
173 # output (installation) path. This requires possibly stripping the
173 # path separator, because otherwise pjoin will not work correctly
174 # path separator, because otherwise pjoin will not work correctly
174 # (pjoin('foo/','/bar') returns '/bar').
175 # (pjoin('foo/','/bar') returns '/bar').
175
176
176 dp_eff = dirpath[lbase:]
177 dp_eff = dirpath[lbase:]
177 if dp_eff.startswith(pathsep):
178 if dp_eff.startswith(pathsep):
178 dp_eff = dp_eff[lpathsep:]
179 dp_eff = dp_eff[lpathsep:]
179 # The output path must be anchored at the out_base marker
180 # The output path must be anchored at the out_base marker
180 out_path = pjoin(out_base,dp_eff)
181 out_path = pjoin(out_base,dp_eff)
181 # Now we can generate the final filenames. Since os.walk only produces
182 # Now we can generate the final filenames. Since os.walk only produces
182 # filenames, we must join back with the dirpath to get full valid file
183 # filenames, we must join back with the dirpath to get full valid file
183 # paths:
184 # paths:
184 pfiles = [pjoin(dirpath,f) for f in filenames]
185 pfiles = [pjoin(dirpath,f) for f in filenames]
185 # Finally, generate the entry we need, which is a pari of (output
186 # Finally, generate the entry we need, which is a pari of (output
186 # path, files) for use as a data_files parameter in install_data.
187 # path, files) for use as a data_files parameter in install_data.
187 out.append((out_path, pfiles))
188 out.append((out_path, pfiles))
188
189
189 return out
190 return out
190
191
191
192
192 def find_data_files():
193 def find_data_files():
193 """
194 """
194 Find IPython's data_files.
195 Find IPython's data_files.
195
196
196 Most of these are docs.
197 Most of these are docs.
197 """
198 """
198
199
199 docdirbase = pjoin('share', 'doc', 'ipython')
200 docdirbase = pjoin('share', 'doc', 'ipython')
200 manpagebase = pjoin('share', 'man', 'man1')
201 manpagebase = pjoin('share', 'man', 'man1')
201
202
202 # Simple file lists can be made by hand
203 # Simple file lists can be made by hand
203 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
204 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
204 if not manpages:
205 if not manpages:
205 # When running from a source tree, the manpages aren't gzipped
206 # When running from a source tree, the manpages aren't gzipped
206 manpages = filter(isfile, glob(pjoin('docs','man','*.1')))
207 manpages = filter(isfile, glob(pjoin('docs','man','*.1')))
207 igridhelpfiles = filter(isfile,
208 igridhelpfiles = filter(isfile,
208 glob(pjoin('IPython','extensions','igrid_help.*')))
209 glob(pjoin('IPython','extensions','igrid_help.*')))
209
210
210 # For nested structures, use the utility above
211 # For nested structures, use the utility above
211 example_files = make_dir_struct(
212 example_files = make_dir_struct(
212 'data',
213 'data',
213 pjoin('docs','examples'),
214 pjoin('docs','examples'),
214 pjoin(docdirbase,'examples')
215 pjoin(docdirbase,'examples')
215 )
216 )
216 manual_files = make_dir_struct(
217 manual_files = make_dir_struct(
217 'data',
218 'data',
218 pjoin('docs','html'),
219 pjoin('docs','html'),
219 pjoin(docdirbase,'manual')
220 pjoin(docdirbase,'manual')
220 )
221 )
221
222
222 # And assemble the entire output list
223 # And assemble the entire output list
223 data_files = [ (manpagebase, manpages),
224 data_files = [ (manpagebase, manpages),
224 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
225 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
225 ] + manual_files + example_files
226 ] + manual_files + example_files
226
227
227 return data_files
228 return data_files
228
229
229
230
230 def make_man_update_target(manpage):
231 def make_man_update_target(manpage):
231 """Return a target_update-compliant tuple for the given manpage.
232 """Return a target_update-compliant tuple for the given manpage.
232
233
233 Parameters
234 Parameters
234 ----------
235 ----------
235 manpage : string
236 manpage : string
236 Name of the manpage, must include the section number (trailing number).
237 Name of the manpage, must include the section number (trailing number).
237
238
238 Example
239 Example
239 -------
240 -------
240
241
241 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
242 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
242 ('docs/man/ipython.1.gz',
243 ('docs/man/ipython.1.gz',
243 ['docs/man/ipython.1'],
244 ['docs/man/ipython.1'],
244 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
245 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
245 """
246 """
246 man_dir = pjoin('docs', 'man')
247 man_dir = pjoin('docs', 'man')
247 manpage_gz = manpage + '.gz'
248 manpage_gz = manpage + '.gz'
248 manpath = pjoin(man_dir, manpage)
249 manpath = pjoin(man_dir, manpage)
249 manpath_gz = pjoin(man_dir, manpage_gz)
250 manpath_gz = pjoin(man_dir, manpage_gz)
250 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
251 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
251 locals() )
252 locals() )
252 return (manpath_gz, [manpath], gz_cmd)
253 return (manpath_gz, [manpath], gz_cmd)
253
254
254 # The two functions below are copied from IPython.utils.path, so we don't need
255 # The two functions below are copied from IPython.utils.path, so we don't need
255 # to import IPython during setup, which fails on Python 3.
256 # to import IPython during setup, which fails on Python 3.
256
257
257 def target_outdated(target,deps):
258 def target_outdated(target,deps):
258 """Determine whether a target is out of date.
259 """Determine whether a target is out of date.
259
260
260 target_outdated(target,deps) -> 1/0
261 target_outdated(target,deps) -> 1/0
261
262
262 deps: list of filenames which MUST exist.
263 deps: list of filenames which MUST exist.
263 target: single filename which may or may not exist.
264 target: single filename which may or may not exist.
264
265
265 If target doesn't exist or is older than any file listed in deps, return
266 If target doesn't exist or is older than any file listed in deps, return
266 true, otherwise return false.
267 true, otherwise return false.
267 """
268 """
268 try:
269 try:
269 target_time = os.path.getmtime(target)
270 target_time = os.path.getmtime(target)
270 except os.error:
271 except os.error:
271 return 1
272 return 1
272 for dep in deps:
273 for dep in deps:
273 dep_time = os.path.getmtime(dep)
274 dep_time = os.path.getmtime(dep)
274 if dep_time > target_time:
275 if dep_time > target_time:
275 #print "For target",target,"Dep failed:",dep # dbg
276 #print "For target",target,"Dep failed:",dep # dbg
276 #print "times (dep,tar):",dep_time,target_time # dbg
277 #print "times (dep,tar):",dep_time,target_time # dbg
277 return 1
278 return 1
278 return 0
279 return 0
279
280
280
281
281 def target_update(target,deps,cmd):
282 def target_update(target,deps,cmd):
282 """Update a target with a given command given a list of dependencies.
283 """Update a target with a given command given a list of dependencies.
283
284
284 target_update(target,deps,cmd) -> runs cmd if target is outdated.
285 target_update(target,deps,cmd) -> runs cmd if target is outdated.
285
286
286 This is just a wrapper around target_outdated() which calls the given
287 This is just a wrapper around target_outdated() which calls the given
287 command if target is outdated."""
288 command if target is outdated."""
288
289
289 if target_outdated(target,deps):
290 if target_outdated(target,deps):
290 system(cmd)
291 system(cmd)
291
292
292 #---------------------------------------------------------------------------
293 #---------------------------------------------------------------------------
293 # Find scripts
294 # Find scripts
294 #---------------------------------------------------------------------------
295 #---------------------------------------------------------------------------
295
296
296 def find_scripts(entry_points=False, suffix=''):
297 def find_scripts(entry_points=False, suffix=''):
297 """Find IPython's scripts.
298 """Find IPython's scripts.
298
299
299 if entry_points is True:
300 if entry_points is True:
300 return setuptools entry_point-style definitions
301 return setuptools entry_point-style definitions
301 else:
302 else:
302 return file paths of plain scripts [default]
303 return file paths of plain scripts [default]
303
304
304 suffix is appended to script names if entry_points is True, so that the
305 suffix is appended to script names if entry_points is True, so that the
305 Python 3 scripts get named "ipython3" etc.
306 Python 3 scripts get named "ipython3" etc.
306 """
307 """
307 if entry_points:
308 if entry_points:
308 console_scripts = [s % suffix for s in [
309 console_scripts = [s % suffix for s in [
309 'ipython%s = IPython.frontend.terminal.ipapp:launch_new_instance',
310 'ipython%s = IPython.frontend.terminal.ipapp:launch_new_instance',
310 'pycolor%s = IPython.utils.PyColorize:main',
311 'pycolor%s = IPython.utils.PyColorize:main',
311 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
312 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
312 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
313 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
313 'iplogger%s = IPython.parallel.apps.iploggerapp:launch_new_instance',
314 'iplogger%s = IPython.parallel.apps.iploggerapp:launch_new_instance',
314 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
315 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
315 'iptest%s = IPython.testing.iptest:main',
316 'iptest%s = IPython.testing.iptest:main',
316 'irunner%s = IPython.lib.irunner:main'
317 'irunner%s = IPython.lib.irunner:main'
317 ]]
318 ]]
318 gui_scripts = [s % suffix for s in [
319 gui_scripts = [s % suffix for s in [
319 'ipython%s-qtconsole = IPython.frontend.qt.console.qtconsoleapp:main',
320 'ipython%s-qtconsole = IPython.frontend.qt.console.qtconsoleapp:main',
320 ]]
321 ]]
321 scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
322 scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
322 else:
323 else:
323 parallel_scripts = pjoin('IPython','parallel','scripts')
324 parallel_scripts = pjoin('IPython','parallel','scripts')
324 main_scripts = pjoin('IPython','scripts')
325 main_scripts = pjoin('IPython','scripts')
325 scripts = [
326 scripts = [
326 pjoin(parallel_scripts, 'ipengine'),
327 pjoin(parallel_scripts, 'ipengine'),
327 pjoin(parallel_scripts, 'ipcontroller'),
328 pjoin(parallel_scripts, 'ipcontroller'),
328 pjoin(parallel_scripts, 'ipcluster'),
329 pjoin(parallel_scripts, 'ipcluster'),
329 pjoin(parallel_scripts, 'iplogger'),
330 pjoin(parallel_scripts, 'iplogger'),
330 pjoin(main_scripts, 'ipython'),
331 pjoin(main_scripts, 'ipython'),
331 pjoin(main_scripts, 'pycolor'),
332 pjoin(main_scripts, 'pycolor'),
332 pjoin(main_scripts, 'irunner'),
333 pjoin(main_scripts, 'irunner'),
333 pjoin(main_scripts, 'iptest')
334 pjoin(main_scripts, 'iptest')
334 ]
335 ]
335 return scripts
336 return scripts
336
337
337 #---------------------------------------------------------------------------
338 #---------------------------------------------------------------------------
338 # Verify all dependencies
339 # Verify all dependencies
339 #---------------------------------------------------------------------------
340 #---------------------------------------------------------------------------
340
341
341 def check_for_dependencies():
342 def check_for_dependencies():
342 """Check for IPython's dependencies.
343 """Check for IPython's dependencies.
343
344
344 This function should NOT be called if running under setuptools!
345 This function should NOT be called if running under setuptools!
345 """
346 """
346 from setupext.setupext import (
347 from setupext.setupext import (
347 print_line, print_raw, print_status,
348 print_line, print_raw, print_status,
348 check_for_sphinx, check_for_pygments,
349 check_for_sphinx, check_for_pygments,
349 check_for_nose, check_for_pexpect,
350 check_for_nose, check_for_pexpect,
350 check_for_pyzmq, check_for_readline
351 check_for_pyzmq, check_for_readline
351 )
352 )
352 print_line()
353 print_line()
353 print_raw("BUILDING IPYTHON")
354 print_raw("BUILDING IPYTHON")
354 print_status('python', sys.version)
355 print_status('python', sys.version)
355 print_status('platform', sys.platform)
356 print_status('platform', sys.platform)
356 if sys.platform == 'win32':
357 if sys.platform == 'win32':
357 print_status('Windows version', sys.getwindowsversion())
358 print_status('Windows version', sys.getwindowsversion())
358
359
359 print_raw("")
360 print_raw("")
360 print_raw("OPTIONAL DEPENDENCIES")
361 print_raw("OPTIONAL DEPENDENCIES")
361
362
362 check_for_sphinx()
363 check_for_sphinx()
363 check_for_pygments()
364 check_for_pygments()
364 check_for_nose()
365 check_for_nose()
365 check_for_pexpect()
366 check_for_pexpect()
366 check_for_pyzmq()
367 check_for_pyzmq()
367 check_for_readline()
368 check_for_readline()
368
369
369 def record_commit_info(pkg_dir, build_cmd=build_py):
370 def record_commit_info(pkg_dir, build_cmd=build_py):
370 """ Return extended build command class for recording commit
371 """ Return extended build command class for recording commit
371
372
372 The extended command tries to run git to find the current commit, getting
373 records git commit in IPython.utils._sysinfo.commit
373 the empty string if it fails. It then writes the commit hash into a file
374
374 in the `pkg_dir` path, named ``.git_commit_info.ini``.
375 for use in IPython.utils.sysinfo.sys_info() calls after installation.
375
376 In due course this information can be used by the package after it is
377 installed, to tell you what commit it was installed from if known.
378
379 To make use of this system, you need a package with a .git_commit_info.ini
380 file - e.g. ``myproject/.git_commit_info.ini`` - that might well look like
381 this::
382
383 # This is an ini file that may contain information about the code state
384 [commit hash]
385 # The line below may contain a valid hash if it has been substituted
386 # during 'git archive'
387 archive_subst_hash=$Format:%h$
388 # This line may be modified by the install process
389 install_hash=
390
391 The .git_commit_info file above is also designed to be used with git
392 substitution - so you probably also want a ``.gitattributes`` file in the
393 root directory of your working tree that contains something like this::
394
395 myproject/.git_commit_info.ini export-subst
396
397 That will cause the ``.git_commit_info.ini`` file to get filled in by ``git
398 archive`` - useful in case someone makes such an archive - for example with
399 via the github 'download source' button.
400
401 Although all the above will work as is, you might consider having something
402 like a ``get_info()`` function in your package to display the commit
403 information at the terminal. See the ``pkg_info.py`` module in the nipy
404 package for an example.
405 """
376 """
377
406 class MyBuildPy(build_cmd):
378 class MyBuildPy(build_cmd):
407 ''' Subclass to write commit data into installation tree '''
379 ''' Subclass to write commit data into installation tree '''
408 def run(self):
380 def run(self):
409 build_cmd.run(self)
381 build_cmd.run(self)
410 import subprocess
382 import subprocess
411 proc = subprocess.Popen('git rev-parse --short HEAD',
383 proc = subprocess.Popen('git rev-parse --short HEAD',
412 stdout=subprocess.PIPE,
384 stdout=subprocess.PIPE,
413 stderr=subprocess.PIPE,
385 stderr=subprocess.PIPE,
414 shell=True)
386 shell=True)
415 repo_commit, _ = proc.communicate()
387 repo_commit, _ = proc.communicate()
388 repo_commit = repo_commit.strip()
416 # We write the installation commit even if it's empty
389 # We write the installation commit even if it's empty
417 cfg_parser = ConfigParser()
390 out_pth = pjoin(self.build_lib, pkg_dir, 'utils', '_sysinfo.py')
418 cfg_parser.read(pjoin(pkg_dir, '.git_commit_info.ini'))
391 with io.open(out_pth, 'w') as out_file:
419 if not cfg_parser.has_section('commit hash'):
392 for line in [
420 # just in case the ini file is empty or doesn't exist, somehow
393 u"# GENERATED BY setup.py",
421 # we don't want the next line to raise
394 u"commit = '%s'" % repo_commit,
422 cfg_parser.add_section('commit hash')
395 ]:
423 cfg_parser.set('commit hash', 'install_hash', repo_commit.decode('ascii'))
396 out_file.write(line + u'\n')
424 out_pth = pjoin(self.build_lib, pkg_dir, '.git_commit_info.ini')
425 out_file = open(out_pth, 'wt')
426 cfg_parser.write(out_file)
427 out_file.close()
428 return MyBuildPy
397 return MyBuildPy
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now