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