##// END OF EJS Templates
Fix how setup.py identifies the Mercurial version....
Jeremy Whitlock -
r8493:4c030ada default
parent child Browse files
Show More
@@ -1,260 +1,260 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # This is the mercurial setup script.
3 # This is the mercurial setup script.
4 #
4 #
5 # 'python setup.py install', or
5 # 'python setup.py install', or
6 # 'python setup.py --help' for more options
6 # 'python setup.py --help' for more options
7
7
8 import sys
8 import sys
9 if not hasattr(sys, 'version_info') or sys.version_info < (2, 3, 0, 'final'):
9 if not hasattr(sys, 'version_info') or sys.version_info < (2, 3, 0, 'final'):
10 raise SystemExit("Mercurial requires python 2.3 or later.")
10 raise SystemExit("Mercurial requires python 2.3 or later.")
11
11
12 # Solaris Python packaging brain damage
12 # Solaris Python packaging brain damage
13 try:
13 try:
14 import hashlib
14 import hashlib
15 sha = hashlib.sha1()
15 sha = hashlib.sha1()
16 except:
16 except:
17 try:
17 try:
18 import sha
18 import sha
19 except:
19 except:
20 raise SystemExit(
20 raise SystemExit(
21 "Couldn't import standard hashlib (incomplete Python install).")
21 "Couldn't import standard hashlib (incomplete Python install).")
22
22
23 try:
23 try:
24 import zlib
24 import zlib
25 except:
25 except:
26 raise SystemExit(
26 raise SystemExit(
27 "Couldn't import standard zlib (incomplete Python install).")
27 "Couldn't import standard zlib (incomplete Python install).")
28
28
29 import os, time
29 import os, time
30 import shutil
30 import shutil
31 import tempfile
31 import tempfile
32 from distutils.core import setup, Extension
32 from distutils.core import setup, Extension
33 from distutils.dist import Distribution
33 from distutils.dist import Distribution
34 from distutils.command.install_data import install_data
34 from distutils.command.install_data import install_data
35 from distutils.command.build import build
35 from distutils.command.build import build
36 from distutils.command.build_py import build_py
36 from distutils.command.build_py import build_py
37 from distutils.spawn import spawn, find_executable
37 from distutils.spawn import spawn, find_executable
38 from distutils.ccompiler import new_compiler
38 from distutils.ccompiler import new_compiler
39
39
40 extra = {}
40 extra = {}
41 scripts = ['hg']
41 scripts = ['hg']
42 if os.name == 'nt':
42 if os.name == 'nt':
43 scripts.append('contrib/win32/hg.bat')
43 scripts.append('contrib/win32/hg.bat')
44
44
45 # simplified version of distutils.ccompiler.CCompiler.has_function
45 # simplified version of distutils.ccompiler.CCompiler.has_function
46 # that actually removes its temporary files.
46 # that actually removes its temporary files.
47 def has_function(cc, funcname):
47 def has_function(cc, funcname):
48 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
48 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
49 devnull = oldstderr = None
49 devnull = oldstderr = None
50 try:
50 try:
51 try:
51 try:
52 fname = os.path.join(tmpdir, 'funcname.c')
52 fname = os.path.join(tmpdir, 'funcname.c')
53 f = open(fname, 'w')
53 f = open(fname, 'w')
54 f.write('int main(void) {\n')
54 f.write('int main(void) {\n')
55 f.write(' %s();\n' % funcname)
55 f.write(' %s();\n' % funcname)
56 f.write('}\n')
56 f.write('}\n')
57 f.close()
57 f.close()
58 # Redirect stderr to /dev/null to hide any error messages
58 # Redirect stderr to /dev/null to hide any error messages
59 # from the compiler.
59 # from the compiler.
60 # This will have to be changed if we ever have to check
60 # This will have to be changed if we ever have to check
61 # for a function on Windows.
61 # for a function on Windows.
62 devnull = open('/dev/null', 'w')
62 devnull = open('/dev/null', 'w')
63 oldstderr = os.dup(sys.stderr.fileno())
63 oldstderr = os.dup(sys.stderr.fileno())
64 os.dup2(devnull.fileno(), sys.stderr.fileno())
64 os.dup2(devnull.fileno(), sys.stderr.fileno())
65 objects = cc.compile([fname])
65 objects = cc.compile([fname])
66 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
66 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
67 except:
67 except:
68 return False
68 return False
69 return True
69 return True
70 finally:
70 finally:
71 if oldstderr is not None:
71 if oldstderr is not None:
72 os.dup2(oldstderr, sys.stderr.fileno())
72 os.dup2(oldstderr, sys.stderr.fileno())
73 if devnull is not None:
73 if devnull is not None:
74 devnull.close()
74 devnull.close()
75 shutil.rmtree(tmpdir)
75 shutil.rmtree(tmpdir)
76
76
77 # py2exe needs to be installed to work
77 # py2exe needs to be installed to work
78 try:
78 try:
79 import py2exe
79 import py2exe
80
80
81 # Help py2exe to find win32com.shell
81 # Help py2exe to find win32com.shell
82 try:
82 try:
83 import modulefinder
83 import modulefinder
84 import win32com
84 import win32com
85 for p in win32com.__path__[1:]: # Take the path to win32comext
85 for p in win32com.__path__[1:]: # Take the path to win32comext
86 modulefinder.AddPackagePath("win32com", p)
86 modulefinder.AddPackagePath("win32com", p)
87 pn = "win32com.shell"
87 pn = "win32com.shell"
88 __import__(pn)
88 __import__(pn)
89 m = sys.modules[pn]
89 m = sys.modules[pn]
90 for p in m.__path__[1:]:
90 for p in m.__path__[1:]:
91 modulefinder.AddPackagePath(pn, p)
91 modulefinder.AddPackagePath(pn, p)
92 except ImportError:
92 except ImportError:
93 pass
93 pass
94
94
95 extra['console'] = ['hg']
95 extra['console'] = ['hg']
96
96
97 except ImportError:
97 except ImportError:
98 pass
98 pass
99
99
100 def getversion():
100 if os.path.exists('.hg'):
101 if not os.path.exists('.hg'):
102 return None # not in a repository
103
104 # execute hg out of this directory with a custom environment which
101 # execute hg out of this directory with a custom environment which
105 # includes the pure Python modules in mercurial/pure
102 # includes the pure Python modules in mercurial/pure
106 pypath = os.environ.get('PYTHONPATH', '')
103 pypath = os.environ.get('PYTHONPATH', '')
107 purepath = os.path.join('mercurial', 'pure')
104 purepath = os.path.join('mercurial', 'pure')
108 os.environ['PYTHONPATH'] = os.pathsep.join(['mercurial', purepath, pypath])
105 os.environ['PYTHONPATH'] = os.pathsep.join(['mercurial', purepath, pypath])
109 os.environ['HGRCPATH'] = '' # do not read any config file
106 os.environ['HGRCPATH'] = '' # do not read any config file
110 cmd = '%s hg id -it' % sys.executable
107 cmd = '%s hg id -it' % sys.executable
108 version = None
111
109
112 try:
110 try:
113 l = os.popen(cmd).read().split()
111 l = os.popen(cmd).read().split()
114 except OSError, e:
112 except OSError, e:
115 print "warning: could not establish Mercurial version: %s" % e
113 print "warning: could not establish Mercurial version: %s" % e
116
114
117 os.environ['PYTHONPATH'] = pypath
115 os.environ['PYTHONPATH'] = pypath
118
116
119 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
117 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
120 l.pop()
118 l.pop()
121 if l:
119 if l:
122 version = l[-1] # latest tag or revision number
120 version = l[-1] # latest tag or revision number
123 if version.endswith('+'):
121 if version.endswith('+'):
124 version += time.strftime('%Y%m%d')
122 version += time.strftime('%Y%m%d')
125 return version
126
123
127 version = getversion()
124 if version:
128 if version:
125 f = file("mercurial/__version__.py", "w")
129 f = file("mercurial/__version__.py", "w")
126 f.write('# this file is autogenerated by setup.py\n')
130 f.write('# this file is autogenerated by setup.py\n')
127 f.write('version = "%s"\n' % version)
131 f.write('version = "%s"\n' % version)
128 f.close()
132 f.close()
129
133 else:
130 try:
134 version = "unknown"
131 from mercurial import __version__
132 version = __version__.version
133 except ImportError:
134 version = 'unknown'
135
135
136 class install_package_data(install_data):
136 class install_package_data(install_data):
137 def finalize_options(self):
137 def finalize_options(self):
138 self.set_undefined_options('install',
138 self.set_undefined_options('install',
139 ('install_lib', 'install_dir'))
139 ('install_lib', 'install_dir'))
140 install_data.finalize_options(self)
140 install_data.finalize_options(self)
141
141
142 class build_mo(build):
142 class build_mo(build):
143
143
144 description = "build translations (.mo files)"
144 description = "build translations (.mo files)"
145
145
146 def run(self):
146 def run(self):
147 if not find_executable('msgfmt'):
147 if not find_executable('msgfmt'):
148 self.warn("could not find msgfmt executable, no translations "
148 self.warn("could not find msgfmt executable, no translations "
149 "will be built")
149 "will be built")
150 return
150 return
151
151
152 podir = 'i18n'
152 podir = 'i18n'
153 if not os.path.isdir(podir):
153 if not os.path.isdir(podir):
154 self.warn("could not find %s/ directory" % podir)
154 self.warn("could not find %s/ directory" % podir)
155 return
155 return
156
156
157 join = os.path.join
157 join = os.path.join
158 for po in os.listdir(podir):
158 for po in os.listdir(podir):
159 if not po.endswith('.po'):
159 if not po.endswith('.po'):
160 continue
160 continue
161 pofile = join(podir, po)
161 pofile = join(podir, po)
162 modir = join('locale', po[:-3], 'LC_MESSAGES')
162 modir = join('locale', po[:-3], 'LC_MESSAGES')
163 mofile = join(modir, 'hg.mo')
163 mofile = join(modir, 'hg.mo')
164 cmd = ['msgfmt', '-v', '-o', mofile, pofile]
164 cmd = ['msgfmt', '-v', '-o', mofile, pofile]
165 if sys.platform != 'sunos5':
165 if sys.platform != 'sunos5':
166 # msgfmt on Solaris does not know about -c
166 # msgfmt on Solaris does not know about -c
167 cmd.append('-c')
167 cmd.append('-c')
168 self.mkpath(modir)
168 self.mkpath(modir)
169 self.make_file([pofile], mofile, spawn, (cmd,))
169 self.make_file([pofile], mofile, spawn, (cmd,))
170 self.distribution.data_files.append((join('mercurial', modir),
170 self.distribution.data_files.append((join('mercurial', modir),
171 [mofile]))
171 [mofile]))
172
172
173 build.sub_commands.append(('build_mo', None))
173 build.sub_commands.append(('build_mo', None))
174
174
175 Distribution.pure = 0
175 Distribution.pure = 0
176 Distribution.global_options.append(('pure', None, "use pure (slow) Python "
176 Distribution.global_options.append(('pure', None, "use pure (slow) Python "
177 "code instead of C extensions"))
177 "code instead of C extensions"))
178
178
179 class hg_build_py(build_py):
179 class hg_build_py(build_py):
180
180
181 def finalize_options(self):
181 def finalize_options(self):
182 build_py.finalize_options(self)
182 build_py.finalize_options(self)
183
183
184 if self.distribution.pure:
184 if self.distribution.pure:
185 if self.py_modules is None:
185 if self.py_modules is None:
186 self.py_modules = []
186 self.py_modules = []
187 for ext in self.distribution.ext_modules:
187 for ext in self.distribution.ext_modules:
188 if ext.name.startswith("mercurial."):
188 if ext.name.startswith("mercurial."):
189 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
189 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
190 self.distribution.ext_modules = []
190 self.distribution.ext_modules = []
191
191
192 def find_modules(self):
192 def find_modules(self):
193 modules = build_py.find_modules(self)
193 modules = build_py.find_modules(self)
194 for module in modules:
194 for module in modules:
195 if module[0] == "mercurial.pure":
195 if module[0] == "mercurial.pure":
196 if module[1] != "__init__":
196 if module[1] != "__init__":
197 yield ("mercurial", module[1], module[2])
197 yield ("mercurial", module[1], module[2])
198 else:
198 else:
199 yield module
199 yield module
200
200
201 cmdclass = {'install_data': install_package_data,
201 cmdclass = {'install_data': install_package_data,
202 'build_mo': build_mo,
202 'build_mo': build_mo,
203 'build_py': hg_build_py}
203 'build_py': hg_build_py}
204
204
205 ext_modules=[
205 ext_modules=[
206 Extension('mercurial.base85', ['mercurial/base85.c']),
206 Extension('mercurial.base85', ['mercurial/base85.c']),
207 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
207 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
208 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
208 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
209 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
209 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
210 Extension('mercurial.parsers', ['mercurial/parsers.c']),
210 Extension('mercurial.parsers', ['mercurial/parsers.c']),
211 ]
211 ]
212
212
213 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert',
213 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert',
214 'hgext.highlight', 'hgext.zeroconf', ]
214 'hgext.highlight', 'hgext.zeroconf', ]
215
215
216 try:
216 try:
217 import msvcrt
217 import msvcrt
218 ext_modules.append(Extension('mercurial.osutil', ['mercurial/osutil.c']))
218 ext_modules.append(Extension('mercurial.osutil', ['mercurial/osutil.c']))
219 except ImportError:
219 except ImportError:
220 pass
220 pass
221
221
222 try:
222 try:
223 import posix
223 import posix
224 ext_modules.append(Extension('mercurial.osutil', ['mercurial/osutil.c']))
224 ext_modules.append(Extension('mercurial.osutil', ['mercurial/osutil.c']))
225
225
226 if sys.platform == 'linux2' and os.uname()[2] > '2.6':
226 if sys.platform == 'linux2' and os.uname()[2] > '2.6':
227 # The inotify extension is only usable with Linux 2.6 kernels.
227 # The inotify extension is only usable with Linux 2.6 kernels.
228 # You also need a reasonably recent C library.
228 # You also need a reasonably recent C library.
229 cc = new_compiler()
229 cc = new_compiler()
230 if has_function(cc, 'inotify_add_watch'):
230 if has_function(cc, 'inotify_add_watch'):
231 ext_modules.append(Extension('hgext.inotify.linux._inotify',
231 ext_modules.append(Extension('hgext.inotify.linux._inotify',
232 ['hgext/inotify/linux/_inotify.c']))
232 ['hgext/inotify/linux/_inotify.c']))
233 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
233 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
234 except ImportError:
234 except ImportError:
235 pass
235 pass
236
236
237 datafiles = []
237 datafiles = []
238 for root in ('templates', 'i18n'):
238 for root in ('templates', 'i18n'):
239 for dir, dirs, files in os.walk(root):
239 for dir, dirs, files in os.walk(root):
240 datafiles.append((os.path.join('mercurial', dir),
240 datafiles.append((os.path.join('mercurial', dir),
241 [os.path.join(dir, file_) for file_ in files]))
241 [os.path.join(dir, file_) for file_ in files]))
242
242
243 setup(name='mercurial',
243 setup(name='mercurial',
244 version=version,
244 version=version,
245 author='Matt Mackall',
245 author='Matt Mackall',
246 author_email='mpm@selenic.com',
246 author_email='mpm@selenic.com',
247 url='http://selenic.com/mercurial',
247 url='http://selenic.com/mercurial',
248 description='Scalable distributed SCM',
248 description='Scalable distributed SCM',
249 license='GNU GPL',
249 license='GNU GPL',
250 scripts=scripts,
250 scripts=scripts,
251 packages=packages,
251 packages=packages,
252 ext_modules=ext_modules,
252 ext_modules=ext_modules,
253 data_files=datafiles,
253 data_files=datafiles,
254 cmdclass=cmdclass,
254 cmdclass=cmdclass,
255 options=dict(py2exe=dict(packages=['hgext', 'email']),
255 options=dict(py2exe=dict(packages=['hgext', 'email']),
256 bdist_mpkg=dict(zipdist=True,
256 bdist_mpkg=dict(zipdist=True,
257 license='COPYING',
257 license='COPYING',
258 readme='contrib/macosx/Readme.html',
258 readme='contrib/macosx/Readme.html',
259 welcome='contrib/macosx/Welcome.html')),
259 welcome='contrib/macosx/Welcome.html')),
260 **extra)
260 **extra)
General Comments 0
You need to be logged in to leave comments. Login now