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