##// END OF EJS Templates
setup: detect Python DLL filename from loaded DLL...
Gregory Szorc -
r29020:ee2e4a2c stable
parent child Browse files
Show More
@@ -1,678 +1,705 b''
1 #
1 #
2 # This is the mercurial setup script.
2 # This is the mercurial setup script.
3 #
3 #
4 # 'python setup.py install', or
4 # 'python setup.py install', or
5 # 'python setup.py --help' for more options
5 # 'python setup.py --help' for more options
6
6
7 import sys, platform
7 import sys, platform
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 6, 0, 'final'):
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 6, 0, 'final'):
9 raise SystemExit("Mercurial requires Python 2.6 or later.")
9 raise SystemExit("Mercurial requires Python 2.6 or later.")
10
10
11 if sys.version_info[0] >= 3:
11 if sys.version_info[0] >= 3:
12 printf = eval('print')
12 printf = eval('print')
13 libdir_escape = 'unicode_escape'
13 libdir_escape = 'unicode_escape'
14 else:
14 else:
15 libdir_escape = 'string_escape'
15 libdir_escape = 'string_escape'
16 def printf(*args, **kwargs):
16 def printf(*args, **kwargs):
17 f = kwargs.get('file', sys.stdout)
17 f = kwargs.get('file', sys.stdout)
18 end = kwargs.get('end', '\n')
18 end = kwargs.get('end', '\n')
19 f.write(b' '.join(args) + end)
19 f.write(b' '.join(args) + end)
20
20
21 # Solaris Python packaging brain damage
21 # Solaris Python packaging brain damage
22 try:
22 try:
23 import hashlib
23 import hashlib
24 sha = hashlib.sha1()
24 sha = hashlib.sha1()
25 except ImportError:
25 except ImportError:
26 try:
26 try:
27 import sha
27 import sha
28 sha.sha # silence unused import warning
28 sha.sha # silence unused import warning
29 except ImportError:
29 except ImportError:
30 raise SystemExit(
30 raise SystemExit(
31 "Couldn't import standard hashlib (incomplete Python install).")
31 "Couldn't import standard hashlib (incomplete Python install).")
32
32
33 try:
33 try:
34 import zlib
34 import zlib
35 zlib.compressobj # silence unused import warning
35 zlib.compressobj # silence unused import warning
36 except ImportError:
36 except ImportError:
37 raise SystemExit(
37 raise SystemExit(
38 "Couldn't import standard zlib (incomplete Python install).")
38 "Couldn't import standard zlib (incomplete Python install).")
39
39
40 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
40 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
41 isironpython = False
41 isironpython = False
42 try:
42 try:
43 isironpython = (platform.python_implementation()
43 isironpython = (platform.python_implementation()
44 .lower().find("ironpython") != -1)
44 .lower().find("ironpython") != -1)
45 except AttributeError:
45 except AttributeError:
46 pass
46 pass
47
47
48 if isironpython:
48 if isironpython:
49 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
49 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
50 else:
50 else:
51 try:
51 try:
52 import bz2
52 import bz2
53 bz2.BZ2Compressor # silence unused import warning
53 bz2.BZ2Compressor # silence unused import warning
54 except ImportError:
54 except ImportError:
55 raise SystemExit(
55 raise SystemExit(
56 "Couldn't import standard bz2 (incomplete Python install).")
56 "Couldn't import standard bz2 (incomplete Python install).")
57
57
58 ispypy = "PyPy" in sys.version
58 ispypy = "PyPy" in sys.version
59
59
60 import ctypes
60 import os, stat, subprocess, time
61 import os, stat, subprocess, time
61 import re
62 import re
62 import shutil
63 import shutil
63 import tempfile
64 import tempfile
64 from distutils import log
65 from distutils import log
65 if 'FORCE_SETUPTOOLS' in os.environ:
66 if 'FORCE_SETUPTOOLS' in os.environ:
66 from setuptools import setup
67 from setuptools import setup
67 else:
68 else:
68 from distutils.core import setup
69 from distutils.core import setup
69 from distutils.core import Command, Extension
70 from distutils.core import Command, Extension
70 from distutils.dist import Distribution
71 from distutils.dist import Distribution
71 from distutils.command.build import build
72 from distutils.command.build import build
72 from distutils.command.build_ext import build_ext
73 from distutils.command.build_ext import build_ext
73 from distutils.command.build_py import build_py
74 from distutils.command.build_py import build_py
74 from distutils.command.build_scripts import build_scripts
75 from distutils.command.build_scripts import build_scripts
75 from distutils.command.install_lib import install_lib
76 from distutils.command.install_lib import install_lib
76 from distutils.command.install_scripts import install_scripts
77 from distutils.command.install_scripts import install_scripts
77 from distutils.spawn import spawn, find_executable
78 from distutils.spawn import spawn, find_executable
78 from distutils import file_util
79 from distutils import file_util
79 from distutils.errors import (
80 from distutils.errors import (
80 CCompilerError,
81 CCompilerError,
81 DistutilsError,
82 DistutilsError,
82 DistutilsExecError,
83 DistutilsExecError,
83 )
84 )
84 from distutils.sysconfig import get_python_inc, get_config_var
85 from distutils.sysconfig import get_python_inc, get_config_var
85 from distutils.version import StrictVersion
86 from distutils.version import StrictVersion
86
87
87 scripts = ['hg']
88 scripts = ['hg']
88 if os.name == 'nt':
89 if os.name == 'nt':
89 # We remove hg.bat if we are able to build hg.exe.
90 # We remove hg.bat if we are able to build hg.exe.
90 scripts.append('contrib/win32/hg.bat')
91 scripts.append('contrib/win32/hg.bat')
91
92
92 # simplified version of distutils.ccompiler.CCompiler.has_function
93 # simplified version of distutils.ccompiler.CCompiler.has_function
93 # that actually removes its temporary files.
94 # that actually removes its temporary files.
94 def hasfunction(cc, funcname):
95 def hasfunction(cc, funcname):
95 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
96 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
96 devnull = oldstderr = None
97 devnull = oldstderr = None
97 try:
98 try:
98 fname = os.path.join(tmpdir, 'funcname.c')
99 fname = os.path.join(tmpdir, 'funcname.c')
99 f = open(fname, 'w')
100 f = open(fname, 'w')
100 f.write('int main(void) {\n')
101 f.write('int main(void) {\n')
101 f.write(' %s();\n' % funcname)
102 f.write(' %s();\n' % funcname)
102 f.write('}\n')
103 f.write('}\n')
103 f.close()
104 f.close()
104 # Redirect stderr to /dev/null to hide any error messages
105 # Redirect stderr to /dev/null to hide any error messages
105 # from the compiler.
106 # from the compiler.
106 # This will have to be changed if we ever have to check
107 # This will have to be changed if we ever have to check
107 # for a function on Windows.
108 # for a function on Windows.
108 devnull = open('/dev/null', 'w')
109 devnull = open('/dev/null', 'w')
109 oldstderr = os.dup(sys.stderr.fileno())
110 oldstderr = os.dup(sys.stderr.fileno())
110 os.dup2(devnull.fileno(), sys.stderr.fileno())
111 os.dup2(devnull.fileno(), sys.stderr.fileno())
111 objects = cc.compile([fname], output_dir=tmpdir)
112 objects = cc.compile([fname], output_dir=tmpdir)
112 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
113 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
113 return True
114 return True
114 except Exception:
115 except Exception:
115 return False
116 return False
116 finally:
117 finally:
117 if oldstderr is not None:
118 if oldstderr is not None:
118 os.dup2(oldstderr, sys.stderr.fileno())
119 os.dup2(oldstderr, sys.stderr.fileno())
119 if devnull is not None:
120 if devnull is not None:
120 devnull.close()
121 devnull.close()
121 shutil.rmtree(tmpdir)
122 shutil.rmtree(tmpdir)
122
123
123 # py2exe needs to be installed to work
124 # py2exe needs to be installed to work
124 try:
125 try:
125 import py2exe
126 import py2exe
126 py2exe.Distribution # silence unused import warning
127 py2exe.Distribution # silence unused import warning
127 py2exeloaded = True
128 py2exeloaded = True
128 # import py2exe's patched Distribution class
129 # import py2exe's patched Distribution class
129 from distutils.core import Distribution
130 from distutils.core import Distribution
130 except ImportError:
131 except ImportError:
131 py2exeloaded = False
132 py2exeloaded = False
132
133
133 def runcmd(cmd, env):
134 def runcmd(cmd, env):
134 if (sys.platform == 'plan9'
135 if (sys.platform == 'plan9'
135 and (sys.version_info[0] == 2 and sys.version_info[1] < 7)):
136 and (sys.version_info[0] == 2 and sys.version_info[1] < 7)):
136 # subprocess kludge to work around issues in half-baked Python
137 # subprocess kludge to work around issues in half-baked Python
137 # ports, notably bichued/python:
138 # ports, notably bichued/python:
138 _, out, err = os.popen3(cmd)
139 _, out, err = os.popen3(cmd)
139 return str(out), str(err)
140 return str(out), str(err)
140 else:
141 else:
141 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
142 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
142 stderr=subprocess.PIPE, env=env)
143 stderr=subprocess.PIPE, env=env)
143 out, err = p.communicate()
144 out, err = p.communicate()
144 return out, err
145 return out, err
145
146
146 def runhg(cmd, env):
147 def runhg(cmd, env):
147 out, err = runcmd(cmd, env)
148 out, err = runcmd(cmd, env)
148 # If root is executing setup.py, but the repository is owned by
149 # If root is executing setup.py, but the repository is owned by
149 # another user (as in "sudo python setup.py install") we will get
150 # another user (as in "sudo python setup.py install") we will get
150 # trust warnings since the .hg/hgrc file is untrusted. That is
151 # trust warnings since the .hg/hgrc file is untrusted. That is
151 # fine, we don't want to load it anyway. Python may warn about
152 # fine, we don't want to load it anyway. Python may warn about
152 # a missing __init__.py in mercurial/locale, we also ignore that.
153 # a missing __init__.py in mercurial/locale, we also ignore that.
153 err = [e for e in err.splitlines()
154 err = [e for e in err.splitlines()
154 if not e.startswith(b'not trusting file') \
155 if not e.startswith(b'not trusting file') \
155 and not e.startswith(b'warning: Not importing') \
156 and not e.startswith(b'warning: Not importing') \
156 and not e.startswith(b'obsolete feature not enabled')]
157 and not e.startswith(b'obsolete feature not enabled')]
157 if err:
158 if err:
158 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
159 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
159 printf(b'\n'.join([b' ' + e for e in err]), file=sys.stderr)
160 printf(b'\n'.join([b' ' + e for e in err]), file=sys.stderr)
160 return ''
161 return ''
161 return out
162 return out
162
163
163 version = ''
164 version = ''
164
165
165 # Execute hg out of this directory with a custom environment which takes care
166 # Execute hg out of this directory with a custom environment which takes care
166 # to not use any hgrc files and do no localization.
167 # to not use any hgrc files and do no localization.
167 env = {'HGMODULEPOLICY': 'py',
168 env = {'HGMODULEPOLICY': 'py',
168 'HGRCPATH': '',
169 'HGRCPATH': '',
169 'LANGUAGE': 'C'}
170 'LANGUAGE': 'C'}
170 if 'LD_LIBRARY_PATH' in os.environ:
171 if 'LD_LIBRARY_PATH' in os.environ:
171 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
172 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
172 if 'SystemRoot' in os.environ:
173 if 'SystemRoot' in os.environ:
173 # Copy SystemRoot into the custom environment for Python 2.6
174 # Copy SystemRoot into the custom environment for Python 2.6
174 # under Windows. Otherwise, the subprocess will fail with
175 # under Windows. Otherwise, the subprocess will fail with
175 # error 0xc0150004. See: http://bugs.python.org/issue3440
176 # error 0xc0150004. See: http://bugs.python.org/issue3440
176 env['SystemRoot'] = os.environ['SystemRoot']
177 env['SystemRoot'] = os.environ['SystemRoot']
177
178
178 if os.path.isdir('.hg'):
179 if os.path.isdir('.hg'):
179 cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
180 cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
180 numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
181 numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
181 hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
182 hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
182 if numerictags: # tag(s) found
183 if numerictags: # tag(s) found
183 version = numerictags[-1]
184 version = numerictags[-1]
184 if hgid.endswith('+'): # propagate the dirty status to the tag
185 if hgid.endswith('+'): # propagate the dirty status to the tag
185 version += '+'
186 version += '+'
186 else: # no tag found
187 else: # no tag found
187 ltagcmd = [sys.executable, 'hg', 'parents', '--template',
188 ltagcmd = [sys.executable, 'hg', 'parents', '--template',
188 '{latesttag}']
189 '{latesttag}']
189 ltag = runhg(ltagcmd, env)
190 ltag = runhg(ltagcmd, env)
190 changessincecmd = [sys.executable, 'hg', 'log', '-T', 'x\n', '-r',
191 changessincecmd = [sys.executable, 'hg', 'log', '-T', 'x\n', '-r',
191 "only(.,'%s')" % ltag]
192 "only(.,'%s')" % ltag]
192 changessince = len(runhg(changessincecmd, env).splitlines())
193 changessince = len(runhg(changessincecmd, env).splitlines())
193 version = '%s+%s-%s' % (ltag, changessince, hgid)
194 version = '%s+%s-%s' % (ltag, changessince, hgid)
194 if version.endswith('+'):
195 if version.endswith('+'):
195 version += time.strftime('%Y%m%d')
196 version += time.strftime('%Y%m%d')
196 elif os.path.exists('.hg_archival.txt'):
197 elif os.path.exists('.hg_archival.txt'):
197 kw = dict([[t.strip() for t in l.split(':', 1)]
198 kw = dict([[t.strip() for t in l.split(':', 1)]
198 for l in open('.hg_archival.txt')])
199 for l in open('.hg_archival.txt')])
199 if 'tag' in kw:
200 if 'tag' in kw:
200 version = kw['tag']
201 version = kw['tag']
201 elif 'latesttag' in kw:
202 elif 'latesttag' in kw:
202 if 'changessincelatesttag' in kw:
203 if 'changessincelatesttag' in kw:
203 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
204 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
204 else:
205 else:
205 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
206 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
206 else:
207 else:
207 version = kw.get('node', '')[:12]
208 version = kw.get('node', '')[:12]
208
209
209 if version:
210 if version:
210 with open("mercurial/__version__.py", "w") as f:
211 with open("mercurial/__version__.py", "w") as f:
211 f.write('# this file is autogenerated by setup.py\n')
212 f.write('# this file is autogenerated by setup.py\n')
212 f.write('version = "%s"\n' % version)
213 f.write('version = "%s"\n' % version)
213
214
214 try:
215 try:
215 oldpolicy = os.environ.get('HGMODULEPOLICY', None)
216 oldpolicy = os.environ.get('HGMODULEPOLICY', None)
216 os.environ['HGMODULEPOLICY'] = 'py'
217 os.environ['HGMODULEPOLICY'] = 'py'
217 from mercurial import __version__
218 from mercurial import __version__
218 version = __version__.version
219 version = __version__.version
219 except ImportError:
220 except ImportError:
220 version = 'unknown'
221 version = 'unknown'
221 finally:
222 finally:
222 if oldpolicy is None:
223 if oldpolicy is None:
223 del os.environ['HGMODULEPOLICY']
224 del os.environ['HGMODULEPOLICY']
224 else:
225 else:
225 os.environ['HGMODULEPOLICY'] = oldpolicy
226 os.environ['HGMODULEPOLICY'] = oldpolicy
226
227
227 class hgbuild(build):
228 class hgbuild(build):
228 # Insert hgbuildmo first so that files in mercurial/locale/ are found
229 # Insert hgbuildmo first so that files in mercurial/locale/ are found
229 # when build_py is run next.
230 # when build_py is run next.
230 sub_commands = [('build_mo', None)] + build.sub_commands
231 sub_commands = [('build_mo', None)] + build.sub_commands
231
232
232 class hgbuildmo(build):
233 class hgbuildmo(build):
233
234
234 description = "build translations (.mo files)"
235 description = "build translations (.mo files)"
235
236
236 def run(self):
237 def run(self):
237 if not find_executable('msgfmt'):
238 if not find_executable('msgfmt'):
238 self.warn("could not find msgfmt executable, no translations "
239 self.warn("could not find msgfmt executable, no translations "
239 "will be built")
240 "will be built")
240 return
241 return
241
242
242 podir = 'i18n'
243 podir = 'i18n'
243 if not os.path.isdir(podir):
244 if not os.path.isdir(podir):
244 self.warn("could not find %s/ directory" % podir)
245 self.warn("could not find %s/ directory" % podir)
245 return
246 return
246
247
247 join = os.path.join
248 join = os.path.join
248 for po in os.listdir(podir):
249 for po in os.listdir(podir):
249 if not po.endswith('.po'):
250 if not po.endswith('.po'):
250 continue
251 continue
251 pofile = join(podir, po)
252 pofile = join(podir, po)
252 modir = join('locale', po[:-3], 'LC_MESSAGES')
253 modir = join('locale', po[:-3], 'LC_MESSAGES')
253 mofile = join(modir, 'hg.mo')
254 mofile = join(modir, 'hg.mo')
254 mobuildfile = join('mercurial', mofile)
255 mobuildfile = join('mercurial', mofile)
255 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
256 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
256 if sys.platform != 'sunos5':
257 if sys.platform != 'sunos5':
257 # msgfmt on Solaris does not know about -c
258 # msgfmt on Solaris does not know about -c
258 cmd.append('-c')
259 cmd.append('-c')
259 self.mkpath(join('mercurial', modir))
260 self.mkpath(join('mercurial', modir))
260 self.make_file([pofile], mobuildfile, spawn, (cmd,))
261 self.make_file([pofile], mobuildfile, spawn, (cmd,))
261
262
262
263
263 class hgdist(Distribution):
264 class hgdist(Distribution):
264 pure = ispypy
265 pure = ispypy
265
266
266 global_options = Distribution.global_options + \
267 global_options = Distribution.global_options + \
267 [('pure', None, "use pure (slow) Python "
268 [('pure', None, "use pure (slow) Python "
268 "code instead of C extensions"),
269 "code instead of C extensions"),
269 ]
270 ]
270
271
271 def has_ext_modules(self):
272 def has_ext_modules(self):
272 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
273 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
273 # too late for some cases
274 # too late for some cases
274 return not self.pure and Distribution.has_ext_modules(self)
275 return not self.pure and Distribution.has_ext_modules(self)
275
276
276 class hgbuildext(build_ext):
277 class hgbuildext(build_ext):
277
278
278 def build_extension(self, ext):
279 def build_extension(self, ext):
279 try:
280 try:
280 build_ext.build_extension(self, ext)
281 build_ext.build_extension(self, ext)
281 except CCompilerError:
282 except CCompilerError:
282 if not getattr(ext, 'optional', False):
283 if not getattr(ext, 'optional', False):
283 raise
284 raise
284 log.warn("Failed to build optional extension '%s' (skipping)",
285 log.warn("Failed to build optional extension '%s' (skipping)",
285 ext.name)
286 ext.name)
286
287
287 class hgbuildscripts(build_scripts):
288 class hgbuildscripts(build_scripts):
288 def run(self):
289 def run(self):
289 if os.name != 'nt' or self.distribution.pure:
290 if os.name != 'nt' or self.distribution.pure:
290 return build_scripts.run(self)
291 return build_scripts.run(self)
291
292
292 exebuilt = False
293 exebuilt = False
293 try:
294 try:
294 self.run_command('build_hgexe')
295 self.run_command('build_hgexe')
295 exebuilt = True
296 exebuilt = True
296 except (DistutilsError, CCompilerError):
297 except (DistutilsError, CCompilerError):
297 log.warn('failed to build optional hg.exe')
298 log.warn('failed to build optional hg.exe')
298
299
299 if exebuilt:
300 if exebuilt:
300 # Copying hg.exe to the scripts build directory ensures it is
301 # Copying hg.exe to the scripts build directory ensures it is
301 # installed by the install_scripts command.
302 # installed by the install_scripts command.
302 hgexecommand = self.get_finalized_command('build_hgexe')
303 hgexecommand = self.get_finalized_command('build_hgexe')
303 dest = os.path.join(self.build_dir, 'hg.exe')
304 dest = os.path.join(self.build_dir, 'hg.exe')
304 self.mkpath(self.build_dir)
305 self.mkpath(self.build_dir)
305 self.copy_file(hgexecommand.hgexepath, dest)
306 self.copy_file(hgexecommand.hgexepath, dest)
306
307
307 # Remove hg.bat because it is redundant with hg.exe.
308 # Remove hg.bat because it is redundant with hg.exe.
308 self.scripts.remove('contrib/win32/hg.bat')
309 self.scripts.remove('contrib/win32/hg.bat')
309
310
310 return build_scripts.run(self)
311 return build_scripts.run(self)
311
312
312 class hgbuildpy(build_py):
313 class hgbuildpy(build_py):
313 def finalize_options(self):
314 def finalize_options(self):
314 build_py.finalize_options(self)
315 build_py.finalize_options(self)
315
316
316 if self.distribution.pure:
317 if self.distribution.pure:
317 self.distribution.ext_modules = []
318 self.distribution.ext_modules = []
318 else:
319 else:
319 h = os.path.join(get_python_inc(), 'Python.h')
320 h = os.path.join(get_python_inc(), 'Python.h')
320 if not os.path.exists(h):
321 if not os.path.exists(h):
321 raise SystemExit('Python headers are required to build '
322 raise SystemExit('Python headers are required to build '
322 'Mercurial but weren\'t found in %s' % h)
323 'Mercurial but weren\'t found in %s' % h)
323
324
324 def run(self):
325 def run(self):
325 if self.distribution.pure:
326 if self.distribution.pure:
326 modulepolicy = 'py'
327 modulepolicy = 'py'
327 else:
328 else:
328 modulepolicy = 'c'
329 modulepolicy = 'c'
329 with open("mercurial/__modulepolicy__.py", "w") as f:
330 with open("mercurial/__modulepolicy__.py", "w") as f:
330 f.write('# this file is autogenerated by setup.py\n')
331 f.write('# this file is autogenerated by setup.py\n')
331 f.write('modulepolicy = "%s"\n' % modulepolicy)
332 f.write('modulepolicy = "%s"\n' % modulepolicy)
332
333
333 build_py.run(self)
334 build_py.run(self)
334
335
335 class buildhgextindex(Command):
336 class buildhgextindex(Command):
336 description = 'generate prebuilt index of hgext (for frozen package)'
337 description = 'generate prebuilt index of hgext (for frozen package)'
337 user_options = []
338 user_options = []
338 _indexfilename = 'hgext/__index__.py'
339 _indexfilename = 'hgext/__index__.py'
339
340
340 def initialize_options(self):
341 def initialize_options(self):
341 pass
342 pass
342
343
343 def finalize_options(self):
344 def finalize_options(self):
344 pass
345 pass
345
346
346 def run(self):
347 def run(self):
347 if os.path.exists(self._indexfilename):
348 if os.path.exists(self._indexfilename):
348 with open(self._indexfilename, 'w') as f:
349 with open(self._indexfilename, 'w') as f:
349 f.write('# empty\n')
350 f.write('# empty\n')
350
351
351 # here no extension enabled, disabled() lists up everything
352 # here no extension enabled, disabled() lists up everything
352 code = ('import pprint; from mercurial import extensions; '
353 code = ('import pprint; from mercurial import extensions; '
353 'pprint.pprint(extensions.disabled())')
354 'pprint.pprint(extensions.disabled())')
354 out, err = runcmd([sys.executable, '-c', code], env)
355 out, err = runcmd([sys.executable, '-c', code], env)
355 if err:
356 if err:
356 raise DistutilsExecError(err)
357 raise DistutilsExecError(err)
357
358
358 with open(self._indexfilename, 'w') as f:
359 with open(self._indexfilename, 'w') as f:
359 f.write('# this file is autogenerated by setup.py\n')
360 f.write('# this file is autogenerated by setup.py\n')
360 f.write('docs = ')
361 f.write('docs = ')
361 f.write(out)
362 f.write(out)
362
363
363 class buildhgexe(build_ext):
364 class buildhgexe(build_ext):
364 description = 'compile hg.exe from mercurial/exewrapper.c'
365 description = 'compile hg.exe from mercurial/exewrapper.c'
365
366
366 def build_extensions(self):
367 def build_extensions(self):
367 if os.name != 'nt':
368 if os.name != 'nt':
368 return
369 return
369 if isinstance(self.compiler, HackedMingw32CCompiler):
370 if isinstance(self.compiler, HackedMingw32CCompiler):
370 self.compiler.compiler_so = self.compiler.compiler # no -mdll
371 self.compiler.compiler_so = self.compiler.compiler # no -mdll
371 self.compiler.dll_libraries = [] # no -lmsrvc90
372 self.compiler.dll_libraries = [] # no -lmsrvc90
372 hv = sys.hexversion
373
373 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
374 # Different Python installs can have different Python library
375 # names. e.g. the official CPython distribution uses pythonXY.dll
376 # and MinGW uses libpythonX.Y.dll.
377 _kernel32 = ctypes.windll.kernel32
378 _kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p,
379 ctypes.c_void_p,
380 ctypes.c_ulong]
381 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
382 size = 1000
383 buf = ctypes.create_string_buffer(size + 1)
384 filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf),
385 size)
386
387 if filelen > 0 and filelen != size:
388 dllbasename = os.path.basename(buf.value)
389 if not dllbasename.lower().endswith('.dll'):
390 raise SystemExit('Python DLL does not end with .dll: %s' %
391 dllbasename)
392 pythonlib = dllbasename[:-4]
393 else:
394 log.warn('could not determine Python DLL filename; '
395 'assuming pythonXY')
396
397 hv = sys.hexversion
398 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
399
400 log.info('using %s as Python library name' % pythonlib)
374 with open('mercurial/hgpythonlib.h', 'wb') as f:
401 with open('mercurial/hgpythonlib.h', 'wb') as f:
375 f.write('/* this file is autogenerated by setup.py */\n')
402 f.write('/* this file is autogenerated by setup.py */\n')
376 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
403 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
377 objects = self.compiler.compile(['mercurial/exewrapper.c'],
404 objects = self.compiler.compile(['mercurial/exewrapper.c'],
378 output_dir=self.build_temp)
405 output_dir=self.build_temp)
379 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
406 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
380 target = os.path.join(dir, 'hg')
407 target = os.path.join(dir, 'hg')
381 self.compiler.link_executable(objects, target,
408 self.compiler.link_executable(objects, target,
382 libraries=[],
409 libraries=[],
383 output_dir=self.build_temp)
410 output_dir=self.build_temp)
384
411
385 @property
412 @property
386 def hgexepath(self):
413 def hgexepath(self):
387 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
414 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
388 return os.path.join(self.build_temp, dir, 'hg.exe')
415 return os.path.join(self.build_temp, dir, 'hg.exe')
389
416
390 class hginstalllib(install_lib):
417 class hginstalllib(install_lib):
391 '''
418 '''
392 This is a specialization of install_lib that replaces the copy_file used
419 This is a specialization of install_lib that replaces the copy_file used
393 there so that it supports setting the mode of files after copying them,
420 there so that it supports setting the mode of files after copying them,
394 instead of just preserving the mode that the files originally had. If your
421 instead of just preserving the mode that the files originally had. If your
395 system has a umask of something like 027, preserving the permissions when
422 system has a umask of something like 027, preserving the permissions when
396 copying will lead to a broken install.
423 copying will lead to a broken install.
397
424
398 Note that just passing keep_permissions=False to copy_file would be
425 Note that just passing keep_permissions=False to copy_file would be
399 insufficient, as it might still be applying a umask.
426 insufficient, as it might still be applying a umask.
400 '''
427 '''
401
428
402 def run(self):
429 def run(self):
403 realcopyfile = file_util.copy_file
430 realcopyfile = file_util.copy_file
404 def copyfileandsetmode(*args, **kwargs):
431 def copyfileandsetmode(*args, **kwargs):
405 src, dst = args[0], args[1]
432 src, dst = args[0], args[1]
406 dst, copied = realcopyfile(*args, **kwargs)
433 dst, copied = realcopyfile(*args, **kwargs)
407 if copied:
434 if copied:
408 st = os.stat(src)
435 st = os.stat(src)
409 # Persist executable bit (apply it to group and other if user
436 # Persist executable bit (apply it to group and other if user
410 # has it)
437 # has it)
411 if st[stat.ST_MODE] & stat.S_IXUSR:
438 if st[stat.ST_MODE] & stat.S_IXUSR:
412 setmode = int('0755', 8)
439 setmode = int('0755', 8)
413 else:
440 else:
414 setmode = int('0644', 8)
441 setmode = int('0644', 8)
415 m = stat.S_IMODE(st[stat.ST_MODE])
442 m = stat.S_IMODE(st[stat.ST_MODE])
416 m = (m & ~int('0777', 8)) | setmode
443 m = (m & ~int('0777', 8)) | setmode
417 os.chmod(dst, m)
444 os.chmod(dst, m)
418 file_util.copy_file = copyfileandsetmode
445 file_util.copy_file = copyfileandsetmode
419 try:
446 try:
420 install_lib.run(self)
447 install_lib.run(self)
421 finally:
448 finally:
422 file_util.copy_file = realcopyfile
449 file_util.copy_file = realcopyfile
423
450
424 class hginstallscripts(install_scripts):
451 class hginstallscripts(install_scripts):
425 '''
452 '''
426 This is a specialization of install_scripts that replaces the @LIBDIR@ with
453 This is a specialization of install_scripts that replaces the @LIBDIR@ with
427 the configured directory for modules. If possible, the path is made relative
454 the configured directory for modules. If possible, the path is made relative
428 to the directory for scripts.
455 to the directory for scripts.
429 '''
456 '''
430
457
431 def initialize_options(self):
458 def initialize_options(self):
432 install_scripts.initialize_options(self)
459 install_scripts.initialize_options(self)
433
460
434 self.install_lib = None
461 self.install_lib = None
435
462
436 def finalize_options(self):
463 def finalize_options(self):
437 install_scripts.finalize_options(self)
464 install_scripts.finalize_options(self)
438 self.set_undefined_options('install',
465 self.set_undefined_options('install',
439 ('install_lib', 'install_lib'))
466 ('install_lib', 'install_lib'))
440
467
441 def run(self):
468 def run(self):
442 install_scripts.run(self)
469 install_scripts.run(self)
443
470
444 # It only makes sense to replace @LIBDIR@ with the install path if
471 # It only makes sense to replace @LIBDIR@ with the install path if
445 # the install path is known. For wheels, the logic below calculates
472 # the install path is known. For wheels, the logic below calculates
446 # the libdir to be "../..". This is because the internal layout of a
473 # the libdir to be "../..". This is because the internal layout of a
447 # wheel archive looks like:
474 # wheel archive looks like:
448 #
475 #
449 # mercurial-3.6.1.data/scripts/hg
476 # mercurial-3.6.1.data/scripts/hg
450 # mercurial/__init__.py
477 # mercurial/__init__.py
451 #
478 #
452 # When installing wheels, the subdirectories of the "<pkg>.data"
479 # When installing wheels, the subdirectories of the "<pkg>.data"
453 # directory are translated to system local paths and files therein
480 # directory are translated to system local paths and files therein
454 # are copied in place. The mercurial/* files are installed into the
481 # are copied in place. The mercurial/* files are installed into the
455 # site-packages directory. However, the site-packages directory
482 # site-packages directory. However, the site-packages directory
456 # isn't known until wheel install time. This means we have no clue
483 # isn't known until wheel install time. This means we have no clue
457 # at wheel generation time what the installed site-packages directory
484 # at wheel generation time what the installed site-packages directory
458 # will be. And, wheels don't appear to provide the ability to register
485 # will be. And, wheels don't appear to provide the ability to register
459 # custom code to run during wheel installation. This all means that
486 # custom code to run during wheel installation. This all means that
460 # we can't reliably set the libdir in wheels: the default behavior
487 # we can't reliably set the libdir in wheels: the default behavior
461 # of looking in sys.path must do.
488 # of looking in sys.path must do.
462
489
463 if (os.path.splitdrive(self.install_dir)[0] !=
490 if (os.path.splitdrive(self.install_dir)[0] !=
464 os.path.splitdrive(self.install_lib)[0]):
491 os.path.splitdrive(self.install_lib)[0]):
465 # can't make relative paths from one drive to another, so use an
492 # can't make relative paths from one drive to another, so use an
466 # absolute path instead
493 # absolute path instead
467 libdir = self.install_lib
494 libdir = self.install_lib
468 else:
495 else:
469 common = os.path.commonprefix((self.install_dir, self.install_lib))
496 common = os.path.commonprefix((self.install_dir, self.install_lib))
470 rest = self.install_dir[len(common):]
497 rest = self.install_dir[len(common):]
471 uplevel = len([n for n in os.path.split(rest) if n])
498 uplevel = len([n for n in os.path.split(rest) if n])
472
499
473 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
500 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
474
501
475 for outfile in self.outfiles:
502 for outfile in self.outfiles:
476 with open(outfile, 'rb') as fp:
503 with open(outfile, 'rb') as fp:
477 data = fp.read()
504 data = fp.read()
478
505
479 # skip binary files
506 # skip binary files
480 if b'\0' in data:
507 if b'\0' in data:
481 continue
508 continue
482
509
483 # During local installs, the shebang will be rewritten to the final
510 # During local installs, the shebang will be rewritten to the final
484 # install path. During wheel packaging, the shebang has a special
511 # install path. During wheel packaging, the shebang has a special
485 # value.
512 # value.
486 if data.startswith(b'#!python'):
513 if data.startswith(b'#!python'):
487 log.info('not rewriting @LIBDIR@ in %s because install path '
514 log.info('not rewriting @LIBDIR@ in %s because install path '
488 'not known' % outfile)
515 'not known' % outfile)
489 continue
516 continue
490
517
491 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
518 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
492 with open(outfile, 'wb') as fp:
519 with open(outfile, 'wb') as fp:
493 fp.write(data)
520 fp.write(data)
494
521
495 cmdclass = {'build': hgbuild,
522 cmdclass = {'build': hgbuild,
496 'build_mo': hgbuildmo,
523 'build_mo': hgbuildmo,
497 'build_ext': hgbuildext,
524 'build_ext': hgbuildext,
498 'build_py': hgbuildpy,
525 'build_py': hgbuildpy,
499 'build_scripts': hgbuildscripts,
526 'build_scripts': hgbuildscripts,
500 'build_hgextindex': buildhgextindex,
527 'build_hgextindex': buildhgextindex,
501 'install_lib': hginstalllib,
528 'install_lib': hginstalllib,
502 'install_scripts': hginstallscripts,
529 'install_scripts': hginstallscripts,
503 'build_hgexe': buildhgexe,
530 'build_hgexe': buildhgexe,
504 }
531 }
505
532
506 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
533 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
507 'mercurial.pure',
534 'mercurial.pure',
508 'hgext', 'hgext.convert', 'hgext.fsmonitor',
535 'hgext', 'hgext.convert', 'hgext.fsmonitor',
509 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
536 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
510 'hgext.largefiles', 'hgext.zeroconf', 'hgext3rd']
537 'hgext.largefiles', 'hgext.zeroconf', 'hgext3rd']
511
538
512 common_depends = ['mercurial/util.h']
539 common_depends = ['mercurial/util.h']
513
540
514 osutil_ldflags = []
541 osutil_ldflags = []
515
542
516 if sys.platform == 'darwin':
543 if sys.platform == 'darwin':
517 osutil_ldflags += ['-framework', 'ApplicationServices']
544 osutil_ldflags += ['-framework', 'ApplicationServices']
518
545
519 extmodules = [
546 extmodules = [
520 Extension('mercurial.base85', ['mercurial/base85.c'],
547 Extension('mercurial.base85', ['mercurial/base85.c'],
521 depends=common_depends),
548 depends=common_depends),
522 Extension('mercurial.bdiff', ['mercurial/bdiff.c'],
549 Extension('mercurial.bdiff', ['mercurial/bdiff.c'],
523 depends=common_depends),
550 depends=common_depends),
524 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
551 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
525 depends=common_depends),
552 depends=common_depends),
526 Extension('mercurial.mpatch', ['mercurial/mpatch.c'],
553 Extension('mercurial.mpatch', ['mercurial/mpatch.c'],
527 depends=common_depends),
554 depends=common_depends),
528 Extension('mercurial.parsers', ['mercurial/dirs.c',
555 Extension('mercurial.parsers', ['mercurial/dirs.c',
529 'mercurial/manifest.c',
556 'mercurial/manifest.c',
530 'mercurial/parsers.c',
557 'mercurial/parsers.c',
531 'mercurial/pathencode.c'],
558 'mercurial/pathencode.c'],
532 depends=common_depends),
559 depends=common_depends),
533 Extension('mercurial.osutil', ['mercurial/osutil.c'],
560 Extension('mercurial.osutil', ['mercurial/osutil.c'],
534 extra_link_args=osutil_ldflags,
561 extra_link_args=osutil_ldflags,
535 depends=common_depends),
562 depends=common_depends),
536 Extension('hgext.fsmonitor.pywatchman.bser',
563 Extension('hgext.fsmonitor.pywatchman.bser',
537 ['hgext/fsmonitor/pywatchman/bser.c']),
564 ['hgext/fsmonitor/pywatchman/bser.c']),
538 ]
565 ]
539
566
540 try:
567 try:
541 from distutils import cygwinccompiler
568 from distutils import cygwinccompiler
542
569
543 # the -mno-cygwin option has been deprecated for years
570 # the -mno-cygwin option has been deprecated for years
544 compiler = cygwinccompiler.Mingw32CCompiler
571 compiler = cygwinccompiler.Mingw32CCompiler
545
572
546 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
573 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
547 def __init__(self, *args, **kwargs):
574 def __init__(self, *args, **kwargs):
548 compiler.__init__(self, *args, **kwargs)
575 compiler.__init__(self, *args, **kwargs)
549 for i in 'compiler compiler_so linker_exe linker_so'.split():
576 for i in 'compiler compiler_so linker_exe linker_so'.split():
550 try:
577 try:
551 getattr(self, i).remove('-mno-cygwin')
578 getattr(self, i).remove('-mno-cygwin')
552 except ValueError:
579 except ValueError:
553 pass
580 pass
554
581
555 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
582 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
556 except ImportError:
583 except ImportError:
557 # the cygwinccompiler package is not available on some Python
584 # the cygwinccompiler package is not available on some Python
558 # distributions like the ones from the optware project for Synology
585 # distributions like the ones from the optware project for Synology
559 # DiskStation boxes
586 # DiskStation boxes
560 class HackedMingw32CCompiler(object):
587 class HackedMingw32CCompiler(object):
561 pass
588 pass
562
589
563 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
590 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
564 'help/*.txt',
591 'help/*.txt',
565 'help/internals/*.txt',
592 'help/internals/*.txt',
566 'default.d/*.rc',
593 'default.d/*.rc',
567 'dummycert.pem']}
594 'dummycert.pem']}
568
595
569 def ordinarypath(p):
596 def ordinarypath(p):
570 return p and p[0] != '.' and p[-1] != '~'
597 return p and p[0] != '.' and p[-1] != '~'
571
598
572 for root in ('templates',):
599 for root in ('templates',):
573 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
600 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
574 curdir = curdir.split(os.sep, 1)[1]
601 curdir = curdir.split(os.sep, 1)[1]
575 dirs[:] = filter(ordinarypath, dirs)
602 dirs[:] = filter(ordinarypath, dirs)
576 for f in filter(ordinarypath, files):
603 for f in filter(ordinarypath, files):
577 f = os.path.join(curdir, f)
604 f = os.path.join(curdir, f)
578 packagedata['mercurial'].append(f)
605 packagedata['mercurial'].append(f)
579
606
580 datafiles = []
607 datafiles = []
581 setupversion = version
608 setupversion = version
582 extra = {}
609 extra = {}
583
610
584 if py2exeloaded:
611 if py2exeloaded:
585 extra['console'] = [
612 extra['console'] = [
586 {'script':'hg',
613 {'script':'hg',
587 'copyright':'Copyright (C) 2005-2016 Matt Mackall and others',
614 'copyright':'Copyright (C) 2005-2016 Matt Mackall and others',
588 'product_version':version}]
615 'product_version':version}]
589 # sub command of 'build' because 'py2exe' does not handle sub_commands
616 # sub command of 'build' because 'py2exe' does not handle sub_commands
590 build.sub_commands.insert(0, ('build_hgextindex', None))
617 build.sub_commands.insert(0, ('build_hgextindex', None))
591 # put dlls in sub directory so that they won't pollute PATH
618 # put dlls in sub directory so that they won't pollute PATH
592 extra['zipfile'] = 'lib/library.zip'
619 extra['zipfile'] = 'lib/library.zip'
593
620
594 if os.name == 'nt':
621 if os.name == 'nt':
595 # Windows binary file versions for exe/dll files must have the
622 # Windows binary file versions for exe/dll files must have the
596 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
623 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
597 setupversion = version.split('+', 1)[0]
624 setupversion = version.split('+', 1)[0]
598
625
599 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
626 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
600 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
627 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
601 if version:
628 if version:
602 version = version[0]
629 version = version[0]
603 if sys.version_info[0] == 3:
630 if sys.version_info[0] == 3:
604 version = version.decode('utf-8')
631 version = version.decode('utf-8')
605 xcode4 = (version.startswith('Xcode') and
632 xcode4 = (version.startswith('Xcode') and
606 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
633 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
607 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
634 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
608 else:
635 else:
609 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
636 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
610 # installed, but instead with only command-line tools. Assume
637 # installed, but instead with only command-line tools. Assume
611 # that only happens on >= Lion, thus no PPC support.
638 # that only happens on >= Lion, thus no PPC support.
612 xcode4 = True
639 xcode4 = True
613 xcode51 = False
640 xcode51 = False
614
641
615 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
642 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
616 # distutils.sysconfig
643 # distutils.sysconfig
617 if xcode4:
644 if xcode4:
618 os.environ['ARCHFLAGS'] = ''
645 os.environ['ARCHFLAGS'] = ''
619
646
620 # XCode 5.1 changes clang such that it now fails to compile if the
647 # XCode 5.1 changes clang such that it now fails to compile if the
621 # -mno-fused-madd flag is passed, but the version of Python shipped with
648 # -mno-fused-madd flag is passed, but the version of Python shipped with
622 # OS X 10.9 Mavericks includes this flag. This causes problems in all
649 # OS X 10.9 Mavericks includes this flag. This causes problems in all
623 # C extension modules, and a bug has been filed upstream at
650 # C extension modules, and a bug has been filed upstream at
624 # http://bugs.python.org/issue21244. We also need to patch this here
651 # http://bugs.python.org/issue21244. We also need to patch this here
625 # so Mercurial can continue to compile in the meantime.
652 # so Mercurial can continue to compile in the meantime.
626 if xcode51:
653 if xcode51:
627 cflags = get_config_var('CFLAGS')
654 cflags = get_config_var('CFLAGS')
628 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
655 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
629 os.environ['CFLAGS'] = (
656 os.environ['CFLAGS'] = (
630 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
657 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
631
658
632 setup(name='mercurial',
659 setup(name='mercurial',
633 version=setupversion,
660 version=setupversion,
634 author='Matt Mackall and many others',
661 author='Matt Mackall and many others',
635 author_email='mercurial@selenic.com',
662 author_email='mercurial@selenic.com',
636 url='https://mercurial-scm.org/',
663 url='https://mercurial-scm.org/',
637 download_url='https://mercurial-scm.org/release/',
664 download_url='https://mercurial-scm.org/release/',
638 description=('Fast scalable distributed SCM (revision control, version '
665 description=('Fast scalable distributed SCM (revision control, version '
639 'control) system'),
666 'control) system'),
640 long_description=('Mercurial is a distributed SCM tool written in Python.'
667 long_description=('Mercurial is a distributed SCM tool written in Python.'
641 ' It is used by a number of large projects that require'
668 ' It is used by a number of large projects that require'
642 ' fast, reliable distributed revision control, such as '
669 ' fast, reliable distributed revision control, such as '
643 'Mozilla.'),
670 'Mozilla.'),
644 license='GNU GPLv2 or any later version',
671 license='GNU GPLv2 or any later version',
645 classifiers=[
672 classifiers=[
646 'Development Status :: 6 - Mature',
673 'Development Status :: 6 - Mature',
647 'Environment :: Console',
674 'Environment :: Console',
648 'Intended Audience :: Developers',
675 'Intended Audience :: Developers',
649 'Intended Audience :: System Administrators',
676 'Intended Audience :: System Administrators',
650 'License :: OSI Approved :: GNU General Public License (GPL)',
677 'License :: OSI Approved :: GNU General Public License (GPL)',
651 'Natural Language :: Danish',
678 'Natural Language :: Danish',
652 'Natural Language :: English',
679 'Natural Language :: English',
653 'Natural Language :: German',
680 'Natural Language :: German',
654 'Natural Language :: Italian',
681 'Natural Language :: Italian',
655 'Natural Language :: Japanese',
682 'Natural Language :: Japanese',
656 'Natural Language :: Portuguese (Brazilian)',
683 'Natural Language :: Portuguese (Brazilian)',
657 'Operating System :: Microsoft :: Windows',
684 'Operating System :: Microsoft :: Windows',
658 'Operating System :: OS Independent',
685 'Operating System :: OS Independent',
659 'Operating System :: POSIX',
686 'Operating System :: POSIX',
660 'Programming Language :: C',
687 'Programming Language :: C',
661 'Programming Language :: Python',
688 'Programming Language :: Python',
662 'Topic :: Software Development :: Version Control',
689 'Topic :: Software Development :: Version Control',
663 ],
690 ],
664 scripts=scripts,
691 scripts=scripts,
665 packages=packages,
692 packages=packages,
666 ext_modules=extmodules,
693 ext_modules=extmodules,
667 data_files=datafiles,
694 data_files=datafiles,
668 package_data=packagedata,
695 package_data=packagedata,
669 cmdclass=cmdclass,
696 cmdclass=cmdclass,
670 distclass=hgdist,
697 distclass=hgdist,
671 options={'py2exe': {'packages': ['hgext', 'email']},
698 options={'py2exe': {'packages': ['hgext', 'email']},
672 'bdist_mpkg': {'zipdist': False,
699 'bdist_mpkg': {'zipdist': False,
673 'license': 'COPYING',
700 'license': 'COPYING',
674 'readme': 'contrib/macosx/Readme.html',
701 'readme': 'contrib/macosx/Readme.html',
675 'welcome': 'contrib/macosx/Welcome.html',
702 'welcome': 'contrib/macosx/Welcome.html',
676 },
703 },
677 },
704 },
678 **extra)
705 **extra)
General Comments 0
You need to be logged in to leave comments. Login now