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