##// END OF EJS Templates
setup: switch to with open as...
timeless -
r28418:121d2571 default
parent child Browse files
Show More
@@ -1,680 +1,673 b''
1 #
1 #
2 # This is the mercurial setup script.
2 # This is the mercurial setup script.
3 #
3 #
4 # 'python setup.py install', or
4 # 'python setup.py install', or
5 # 'python setup.py --help' for more options
5 # 'python setup.py --help' for more options
6
6
7 import sys, platform
7 import sys, platform
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 6, 0, 'final'):
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 6, 0, 'final'):
9 raise SystemExit("Mercurial requires Python 2.6 or later.")
9 raise SystemExit("Mercurial requires Python 2.6 or later.")
10
10
11 if sys.version_info[0] >= 3:
11 if sys.version_info[0] >= 3:
12 printf = eval('print')
12 printf = eval('print')
13 libdir_escape = 'unicode_escape'
13 libdir_escape = 'unicode_escape'
14 else:
14 else:
15 libdir_escape = 'string_escape'
15 libdir_escape = 'string_escape'
16 def printf(*args, **kwargs):
16 def printf(*args, **kwargs):
17 f = kwargs.get('file', sys.stdout)
17 f = kwargs.get('file', sys.stdout)
18 end = kwargs.get('end', '\n')
18 end = kwargs.get('end', '\n')
19 f.write(b' '.join(args) + end)
19 f.write(b' '.join(args) + end)
20
20
21 # Solaris Python packaging brain damage
21 # Solaris Python packaging brain damage
22 try:
22 try:
23 import hashlib
23 import hashlib
24 sha = hashlib.sha1()
24 sha = hashlib.sha1()
25 except ImportError:
25 except ImportError:
26 try:
26 try:
27 import sha
27 import sha
28 sha.sha # silence unused import warning
28 sha.sha # silence unused import warning
29 except ImportError:
29 except ImportError:
30 raise SystemExit(
30 raise SystemExit(
31 "Couldn't import standard hashlib (incomplete Python install).")
31 "Couldn't import standard hashlib (incomplete Python install).")
32
32
33 try:
33 try:
34 import zlib
34 import zlib
35 zlib.compressobj # silence unused import warning
35 zlib.compressobj # silence unused import warning
36 except ImportError:
36 except ImportError:
37 raise SystemExit(
37 raise SystemExit(
38 "Couldn't import standard zlib (incomplete Python install).")
38 "Couldn't import standard zlib (incomplete Python install).")
39
39
40 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
40 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
41 isironpython = False
41 isironpython = False
42 try:
42 try:
43 isironpython = (platform.python_implementation()
43 isironpython = (platform.python_implementation()
44 .lower().find("ironpython") != -1)
44 .lower().find("ironpython") != -1)
45 except AttributeError:
45 except AttributeError:
46 pass
46 pass
47
47
48 if isironpython:
48 if isironpython:
49 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
49 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
50 else:
50 else:
51 try:
51 try:
52 import bz2
52 import bz2
53 bz2.BZ2Compressor # silence unused import warning
53 bz2.BZ2Compressor # silence unused import warning
54 except ImportError:
54 except ImportError:
55 raise SystemExit(
55 raise SystemExit(
56 "Couldn't import standard bz2 (incomplete Python install).")
56 "Couldn't import standard bz2 (incomplete Python install).")
57
57
58 ispypy = "PyPy" in sys.version
58 ispypy = "PyPy" in sys.version
59
59
60 import 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 f = open("mercurial/__version__.py", "w")
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 f.close()
214
215
213
216 try:
214 try:
217 from mercurial import __version__
215 from mercurial import __version__
218 version = __version__.version
216 version = __version__.version
219 except ImportError:
217 except ImportError:
220 version = 'unknown'
218 version = 'unknown'
221
219
222 class hgbuild(build):
220 class hgbuild(build):
223 # Insert hgbuildmo first so that files in mercurial/locale/ are found
221 # Insert hgbuildmo first so that files in mercurial/locale/ are found
224 # when build_py is run next.
222 # when build_py is run next.
225 sub_commands = [('build_mo', None)] + build.sub_commands
223 sub_commands = [('build_mo', None)] + build.sub_commands
226
224
227 class hgbuildmo(build):
225 class hgbuildmo(build):
228
226
229 description = "build translations (.mo files)"
227 description = "build translations (.mo files)"
230
228
231 def run(self):
229 def run(self):
232 if not find_executable('msgfmt'):
230 if not find_executable('msgfmt'):
233 self.warn("could not find msgfmt executable, no translations "
231 self.warn("could not find msgfmt executable, no translations "
234 "will be built")
232 "will be built")
235 return
233 return
236
234
237 podir = 'i18n'
235 podir = 'i18n'
238 if not os.path.isdir(podir):
236 if not os.path.isdir(podir):
239 self.warn("could not find %s/ directory" % podir)
237 self.warn("could not find %s/ directory" % podir)
240 return
238 return
241
239
242 join = os.path.join
240 join = os.path.join
243 for po in os.listdir(podir):
241 for po in os.listdir(podir):
244 if not po.endswith('.po'):
242 if not po.endswith('.po'):
245 continue
243 continue
246 pofile = join(podir, po)
244 pofile = join(podir, po)
247 modir = join('locale', po[:-3], 'LC_MESSAGES')
245 modir = join('locale', po[:-3], 'LC_MESSAGES')
248 mofile = join(modir, 'hg.mo')
246 mofile = join(modir, 'hg.mo')
249 mobuildfile = join('mercurial', mofile)
247 mobuildfile = join('mercurial', mofile)
250 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
248 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
251 if sys.platform != 'sunos5':
249 if sys.platform != 'sunos5':
252 # msgfmt on Solaris does not know about -c
250 # msgfmt on Solaris does not know about -c
253 cmd.append('-c')
251 cmd.append('-c')
254 self.mkpath(join('mercurial', modir))
252 self.mkpath(join('mercurial', modir))
255 self.make_file([pofile], mobuildfile, spawn, (cmd,))
253 self.make_file([pofile], mobuildfile, spawn, (cmd,))
256
254
257
255
258 class hgdist(Distribution):
256 class hgdist(Distribution):
259 pure = ispypy
257 pure = ispypy
260
258
261 global_options = Distribution.global_options + \
259 global_options = Distribution.global_options + \
262 [('pure', None, "use pure (slow) Python "
260 [('pure', None, "use pure (slow) Python "
263 "code instead of C extensions"),
261 "code instead of C extensions"),
264 ]
262 ]
265
263
266 def has_ext_modules(self):
264 def has_ext_modules(self):
267 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
265 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
268 # too late for some cases
266 # too late for some cases
269 return not self.pure and Distribution.has_ext_modules(self)
267 return not self.pure and Distribution.has_ext_modules(self)
270
268
271 class hgbuildext(build_ext):
269 class hgbuildext(build_ext):
272
270
273 def build_extension(self, ext):
271 def build_extension(self, ext):
274 try:
272 try:
275 build_ext.build_extension(self, ext)
273 build_ext.build_extension(self, ext)
276 except CCompilerError:
274 except CCompilerError:
277 if not getattr(ext, 'optional', False):
275 if not getattr(ext, 'optional', False):
278 raise
276 raise
279 log.warn("Failed to build optional extension '%s' (skipping)",
277 log.warn("Failed to build optional extension '%s' (skipping)",
280 ext.name)
278 ext.name)
281
279
282 class hgbuildscripts(build_scripts):
280 class hgbuildscripts(build_scripts):
283 def run(self):
281 def run(self):
284 if os.name != 'nt' or self.distribution.pure:
282 if os.name != 'nt' or self.distribution.pure:
285 return build_scripts.run(self)
283 return build_scripts.run(self)
286
284
287 exebuilt = False
285 exebuilt = False
288 try:
286 try:
289 self.run_command('build_hgexe')
287 self.run_command('build_hgexe')
290 exebuilt = True
288 exebuilt = True
291 except (DistutilsError, CCompilerError):
289 except (DistutilsError, CCompilerError):
292 log.warn('failed to build optional hg.exe')
290 log.warn('failed to build optional hg.exe')
293
291
294 if exebuilt:
292 if exebuilt:
295 # Copying hg.exe to the scripts build directory ensures it is
293 # Copying hg.exe to the scripts build directory ensures it is
296 # installed by the install_scripts command.
294 # installed by the install_scripts command.
297 hgexecommand = self.get_finalized_command('build_hgexe')
295 hgexecommand = self.get_finalized_command('build_hgexe')
298 dest = os.path.join(self.build_dir, 'hg.exe')
296 dest = os.path.join(self.build_dir, 'hg.exe')
299 self.mkpath(self.build_dir)
297 self.mkpath(self.build_dir)
300 self.copy_file(hgexecommand.hgexepath, dest)
298 self.copy_file(hgexecommand.hgexepath, dest)
301
299
302 # Remove hg.bat because it is redundant with hg.exe.
300 # Remove hg.bat because it is redundant with hg.exe.
303 self.scripts.remove('contrib/win32/hg.bat')
301 self.scripts.remove('contrib/win32/hg.bat')
304
302
305 return build_scripts.run(self)
303 return build_scripts.run(self)
306
304
307 class hgbuildpy(build_py):
305 class hgbuildpy(build_py):
308 def finalize_options(self):
306 def finalize_options(self):
309 build_py.finalize_options(self)
307 build_py.finalize_options(self)
310
308
311 if self.distribution.pure:
309 if self.distribution.pure:
312 self.distribution.ext_modules = []
310 self.distribution.ext_modules = []
313 else:
311 else:
314 h = os.path.join(get_python_inc(), 'Python.h')
312 h = os.path.join(get_python_inc(), 'Python.h')
315 if not os.path.exists(h):
313 if not os.path.exists(h):
316 raise SystemExit('Python headers are required to build '
314 raise SystemExit('Python headers are required to build '
317 'Mercurial but weren\'t found in %s' % h)
315 'Mercurial but weren\'t found in %s' % h)
318
316
319 def copy_file(self, *args, **kwargs):
317 def copy_file(self, *args, **kwargs):
320 dst, copied = build_py.copy_file(self, *args, **kwargs)
318 dst, copied = build_py.copy_file(self, *args, **kwargs)
321
319
322 if copied and dst.endswith('__init__.py'):
320 if copied and dst.endswith('__init__.py'):
323 if self.distribution.pure:
321 if self.distribution.pure:
324 modulepolicy = 'py'
322 modulepolicy = 'py'
325 else:
323 else:
326 modulepolicy = 'c'
324 modulepolicy = 'c'
327 content = open(dst, 'rb').read()
325 content = open(dst, 'rb').read()
328 content = content.replace(b'@MODULELOADPOLICY@',
326 content = content.replace(b'@MODULELOADPOLICY@',
329 modulepolicy.encode(libdir_escape))
327 modulepolicy.encode(libdir_escape))
330 with open(dst, 'wb') as fh:
328 with open(dst, 'wb') as fh:
331 fh.write(content)
329 fh.write(content)
332
330
333 return dst, copied
331 return dst, copied
334
332
335 class buildhgextindex(Command):
333 class buildhgextindex(Command):
336 description = 'generate prebuilt index of hgext (for frozen package)'
334 description = 'generate prebuilt index of hgext (for frozen package)'
337 user_options = []
335 user_options = []
338 _indexfilename = 'hgext/__index__.py'
336 _indexfilename = 'hgext/__index__.py'
339
337
340 def initialize_options(self):
338 def initialize_options(self):
341 pass
339 pass
342
340
343 def finalize_options(self):
341 def finalize_options(self):
344 pass
342 pass
345
343
346 def run(self):
344 def run(self):
347 if os.path.exists(self._indexfilename):
345 if os.path.exists(self._indexfilename):
348 f = open(self._indexfilename, 'w')
346 with open(self._indexfilename, 'w') as f:
349 f.write('# empty\n')
347 f.write('# empty\n')
350 f.close()
351
348
352 # here no extension enabled, disabled() lists up everything
349 # here no extension enabled, disabled() lists up everything
353 code = ('import pprint; from mercurial import extensions; '
350 code = ('import pprint; from mercurial import extensions; '
354 'pprint.pprint(extensions.disabled())')
351 'pprint.pprint(extensions.disabled())')
355 out, err = runcmd([sys.executable, '-c', code], env)
352 out, err = runcmd([sys.executable, '-c', code], env)
356 if err:
353 if err:
357 raise DistutilsExecError(err)
354 raise DistutilsExecError(err)
358
355
359 f = open(self._indexfilename, 'w')
356 with open(self._indexfilename, 'w') as f:
360 f.write('# this file is autogenerated by setup.py\n')
357 f.write('# this file is autogenerated by setup.py\n')
361 f.write('docs = ')
358 f.write('docs = ')
362 f.write(out)
359 f.write(out)
363 f.close()
364
360
365 class buildhgexe(build_ext):
361 class buildhgexe(build_ext):
366 description = 'compile hg.exe from mercurial/exewrapper.c'
362 description = 'compile hg.exe from mercurial/exewrapper.c'
367
363
368 def build_extensions(self):
364 def build_extensions(self):
369 if os.name != 'nt':
365 if os.name != 'nt':
370 return
366 return
371 if isinstance(self.compiler, HackedMingw32CCompiler):
367 if isinstance(self.compiler, HackedMingw32CCompiler):
372 self.compiler.compiler_so = self.compiler.compiler # no -mdll
368 self.compiler.compiler_so = self.compiler.compiler # no -mdll
373 self.compiler.dll_libraries = [] # no -lmsrvc90
369 self.compiler.dll_libraries = [] # no -lmsrvc90
374 hv = sys.hexversion
370 hv = sys.hexversion
375 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
371 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
376 f = open('mercurial/hgpythonlib.h', 'wb')
372 with open('mercurial/hgpythonlib.h', 'wb') as f:
377 f.write('/* this file is autogenerated by setup.py */\n')
373 f.write('/* this file is autogenerated by setup.py */\n')
378 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
374 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
379 f.close()
380 objects = self.compiler.compile(['mercurial/exewrapper.c'],
375 objects = self.compiler.compile(['mercurial/exewrapper.c'],
381 output_dir=self.build_temp)
376 output_dir=self.build_temp)
382 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
377 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
383 target = os.path.join(dir, 'hg')
378 target = os.path.join(dir, 'hg')
384 self.compiler.link_executable(objects, target,
379 self.compiler.link_executable(objects, target,
385 libraries=[],
380 libraries=[],
386 output_dir=self.build_temp)
381 output_dir=self.build_temp)
387
382
388 @property
383 @property
389 def hgexepath(self):
384 def hgexepath(self):
390 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
385 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
391 return os.path.join(self.build_temp, dir, 'hg.exe')
386 return os.path.join(self.build_temp, dir, 'hg.exe')
392
387
393 class hginstalllib(install_lib):
388 class hginstalllib(install_lib):
394 '''
389 '''
395 This is a specialization of install_lib that replaces the copy_file used
390 This is a specialization of install_lib that replaces the copy_file used
396 there so that it supports setting the mode of files after copying them,
391 there so that it supports setting the mode of files after copying them,
397 instead of just preserving the mode that the files originally had. If your
392 instead of just preserving the mode that the files originally had. If your
398 system has a umask of something like 027, preserving the permissions when
393 system has a umask of something like 027, preserving the permissions when
399 copying will lead to a broken install.
394 copying will lead to a broken install.
400
395
401 Note that just passing keep_permissions=False to copy_file would be
396 Note that just passing keep_permissions=False to copy_file would be
402 insufficient, as it might still be applying a umask.
397 insufficient, as it might still be applying a umask.
403 '''
398 '''
404
399
405 def run(self):
400 def run(self):
406 realcopyfile = file_util.copy_file
401 realcopyfile = file_util.copy_file
407 def copyfileandsetmode(*args, **kwargs):
402 def copyfileandsetmode(*args, **kwargs):
408 src, dst = args[0], args[1]
403 src, dst = args[0], args[1]
409 dst, copied = realcopyfile(*args, **kwargs)
404 dst, copied = realcopyfile(*args, **kwargs)
410 if copied:
405 if copied:
411 st = os.stat(src)
406 st = os.stat(src)
412 # Persist executable bit (apply it to group and other if user
407 # Persist executable bit (apply it to group and other if user
413 # has it)
408 # has it)
414 if st[stat.ST_MODE] & stat.S_IXUSR:
409 if st[stat.ST_MODE] & stat.S_IXUSR:
415 setmode = int('0755', 8)
410 setmode = int('0755', 8)
416 else:
411 else:
417 setmode = int('0644', 8)
412 setmode = int('0644', 8)
418 m = stat.S_IMODE(st[stat.ST_MODE])
413 m = stat.S_IMODE(st[stat.ST_MODE])
419 m = (m & ~int('0777', 8)) | setmode
414 m = (m & ~int('0777', 8)) | setmode
420 os.chmod(dst, m)
415 os.chmod(dst, m)
421 file_util.copy_file = copyfileandsetmode
416 file_util.copy_file = copyfileandsetmode
422 try:
417 try:
423 install_lib.run(self)
418 install_lib.run(self)
424 finally:
419 finally:
425 file_util.copy_file = realcopyfile
420 file_util.copy_file = realcopyfile
426
421
427 class hginstallscripts(install_scripts):
422 class hginstallscripts(install_scripts):
428 '''
423 '''
429 This is a specialization of install_scripts that replaces the @LIBDIR@ with
424 This is a specialization of install_scripts that replaces the @LIBDIR@ with
430 the configured directory for modules. If possible, the path is made relative
425 the configured directory for modules. If possible, the path is made relative
431 to the directory for scripts.
426 to the directory for scripts.
432 '''
427 '''
433
428
434 def initialize_options(self):
429 def initialize_options(self):
435 install_scripts.initialize_options(self)
430 install_scripts.initialize_options(self)
436
431
437 self.install_lib = None
432 self.install_lib = None
438
433
439 def finalize_options(self):
434 def finalize_options(self):
440 install_scripts.finalize_options(self)
435 install_scripts.finalize_options(self)
441 self.set_undefined_options('install',
436 self.set_undefined_options('install',
442 ('install_lib', 'install_lib'))
437 ('install_lib', 'install_lib'))
443
438
444 def run(self):
439 def run(self):
445 install_scripts.run(self)
440 install_scripts.run(self)
446
441
447 # It only makes sense to replace @LIBDIR@ with the install path if
442 # It only makes sense to replace @LIBDIR@ with the install path if
448 # the install path is known. For wheels, the logic below calculates
443 # the install path is known. For wheels, the logic below calculates
449 # the libdir to be "../..". This is because the internal layout of a
444 # the libdir to be "../..". This is because the internal layout of a
450 # wheel archive looks like:
445 # wheel archive looks like:
451 #
446 #
452 # mercurial-3.6.1.data/scripts/hg
447 # mercurial-3.6.1.data/scripts/hg
453 # mercurial/__init__.py
448 # mercurial/__init__.py
454 #
449 #
455 # When installing wheels, the subdirectories of the "<pkg>.data"
450 # When installing wheels, the subdirectories of the "<pkg>.data"
456 # directory are translated to system local paths and files therein
451 # directory are translated to system local paths and files therein
457 # are copied in place. The mercurial/* files are installed into the
452 # are copied in place. The mercurial/* files are installed into the
458 # site-packages directory. However, the site-packages directory
453 # site-packages directory. However, the site-packages directory
459 # isn't known until wheel install time. This means we have no clue
454 # isn't known until wheel install time. This means we have no clue
460 # at wheel generation time what the installed site-packages directory
455 # at wheel generation time what the installed site-packages directory
461 # will be. And, wheels don't appear to provide the ability to register
456 # will be. And, wheels don't appear to provide the ability to register
462 # custom code to run during wheel installation. This all means that
457 # custom code to run during wheel installation. This all means that
463 # we can't reliably set the libdir in wheels: the default behavior
458 # we can't reliably set the libdir in wheels: the default behavior
464 # of looking in sys.path must do.
459 # of looking in sys.path must do.
465
460
466 if (os.path.splitdrive(self.install_dir)[0] !=
461 if (os.path.splitdrive(self.install_dir)[0] !=
467 os.path.splitdrive(self.install_lib)[0]):
462 os.path.splitdrive(self.install_lib)[0]):
468 # can't make relative paths from one drive to another, so use an
463 # can't make relative paths from one drive to another, so use an
469 # absolute path instead
464 # absolute path instead
470 libdir = self.install_lib
465 libdir = self.install_lib
471 else:
466 else:
472 common = os.path.commonprefix((self.install_dir, self.install_lib))
467 common = os.path.commonprefix((self.install_dir, self.install_lib))
473 rest = self.install_dir[len(common):]
468 rest = self.install_dir[len(common):]
474 uplevel = len([n for n in os.path.split(rest) if n])
469 uplevel = len([n for n in os.path.split(rest) if n])
475
470
476 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
471 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
477
472
478 for outfile in self.outfiles:
473 for outfile in self.outfiles:
479 fp = open(outfile, 'rb')
474 with open(outfile, 'rb') as fp:
480 data = fp.read()
475 data = fp.read()
481 fp.close()
482
476
483 # skip binary files
477 # skip binary files
484 if b'\0' in data:
478 if b'\0' in data:
485 continue
479 continue
486
480
487 # During local installs, the shebang will be rewritten to the final
481 # During local installs, the shebang will be rewritten to the final
488 # install path. During wheel packaging, the shebang has a special
482 # install path. During wheel packaging, the shebang has a special
489 # value.
483 # value.
490 if data.startswith(b'#!python'):
484 if data.startswith(b'#!python'):
491 log.info('not rewriting @LIBDIR@ in %s because install path '
485 log.info('not rewriting @LIBDIR@ in %s because install path '
492 'not known' % outfile)
486 'not known' % outfile)
493 continue
487 continue
494
488
495 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
489 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
496 fp = open(outfile, 'wb')
490 with open(outfile, 'wb') as fp:
497 fp.write(data)
491 fp.write(data)
498 fp.close()
499
492
500 cmdclass = {'build': hgbuild,
493 cmdclass = {'build': hgbuild,
501 'build_mo': hgbuildmo,
494 'build_mo': hgbuildmo,
502 'build_ext': hgbuildext,
495 'build_ext': hgbuildext,
503 'build_py': hgbuildpy,
496 'build_py': hgbuildpy,
504 'build_scripts': hgbuildscripts,
497 'build_scripts': hgbuildscripts,
505 'build_hgextindex': buildhgextindex,
498 'build_hgextindex': buildhgextindex,
506 'install_lib': hginstalllib,
499 'install_lib': hginstalllib,
507 'install_scripts': hginstallscripts,
500 'install_scripts': hginstallscripts,
508 'build_hgexe': buildhgexe,
501 'build_hgexe': buildhgexe,
509 }
502 }
510
503
511 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
504 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
512 'mercurial.pure',
505 'mercurial.pure',
513 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
506 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
514 'hgext.largefiles']
507 'hgext.largefiles']
515
508
516 common_depends = ['mercurial/util.h']
509 common_depends = ['mercurial/util.h']
517
510
518 osutil_ldflags = []
511 osutil_ldflags = []
519
512
520 if sys.platform == 'darwin':
513 if sys.platform == 'darwin':
521 osutil_ldflags += ['-framework', 'ApplicationServices']
514 osutil_ldflags += ['-framework', 'ApplicationServices']
522
515
523 extmodules = [
516 extmodules = [
524 Extension('mercurial.base85', ['mercurial/base85.c'],
517 Extension('mercurial.base85', ['mercurial/base85.c'],
525 depends=common_depends),
518 depends=common_depends),
526 Extension('mercurial.bdiff', ['mercurial/bdiff.c'],
519 Extension('mercurial.bdiff', ['mercurial/bdiff.c'],
527 depends=common_depends),
520 depends=common_depends),
528 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
521 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
529 depends=common_depends),
522 depends=common_depends),
530 Extension('mercurial.mpatch', ['mercurial/mpatch.c'],
523 Extension('mercurial.mpatch', ['mercurial/mpatch.c'],
531 depends=common_depends),
524 depends=common_depends),
532 Extension('mercurial.parsers', ['mercurial/dirs.c',
525 Extension('mercurial.parsers', ['mercurial/dirs.c',
533 'mercurial/manifest.c',
526 'mercurial/manifest.c',
534 'mercurial/parsers.c',
527 'mercurial/parsers.c',
535 'mercurial/pathencode.c'],
528 'mercurial/pathencode.c'],
536 depends=common_depends),
529 depends=common_depends),
537 Extension('mercurial.osutil', ['mercurial/osutil.c'],
530 Extension('mercurial.osutil', ['mercurial/osutil.c'],
538 extra_link_args=osutil_ldflags,
531 extra_link_args=osutil_ldflags,
539 depends=common_depends),
532 depends=common_depends),
540 ]
533 ]
541
534
542 try:
535 try:
543 from distutils import cygwinccompiler
536 from distutils import cygwinccompiler
544
537
545 # the -mno-cygwin option has been deprecated for years
538 # the -mno-cygwin option has been deprecated for years
546 compiler = cygwinccompiler.Mingw32CCompiler
539 compiler = cygwinccompiler.Mingw32CCompiler
547
540
548 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
541 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
549 def __init__(self, *args, **kwargs):
542 def __init__(self, *args, **kwargs):
550 compiler.__init__(self, *args, **kwargs)
543 compiler.__init__(self, *args, **kwargs)
551 for i in 'compiler compiler_so linker_exe linker_so'.split():
544 for i in 'compiler compiler_so linker_exe linker_so'.split():
552 try:
545 try:
553 getattr(self, i).remove('-mno-cygwin')
546 getattr(self, i).remove('-mno-cygwin')
554 except ValueError:
547 except ValueError:
555 pass
548 pass
556
549
557 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
550 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
558 except ImportError:
551 except ImportError:
559 # the cygwinccompiler package is not available on some Python
552 # the cygwinccompiler package is not available on some Python
560 # distributions like the ones from the optware project for Synology
553 # distributions like the ones from the optware project for Synology
561 # DiskStation boxes
554 # DiskStation boxes
562 class HackedMingw32CCompiler(object):
555 class HackedMingw32CCompiler(object):
563 pass
556 pass
564
557
565 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
558 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
566 'help/*.txt',
559 'help/*.txt',
567 'help/internals/*.txt',
560 'help/internals/*.txt',
568 'default.d/*.rc',
561 'default.d/*.rc',
569 'dummycert.pem']}
562 'dummycert.pem']}
570
563
571 def ordinarypath(p):
564 def ordinarypath(p):
572 return p and p[0] != '.' and p[-1] != '~'
565 return p and p[0] != '.' and p[-1] != '~'
573
566
574 for root in ('templates',):
567 for root in ('templates',):
575 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
568 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
576 curdir = curdir.split(os.sep, 1)[1]
569 curdir = curdir.split(os.sep, 1)[1]
577 dirs[:] = filter(ordinarypath, dirs)
570 dirs[:] = filter(ordinarypath, dirs)
578 for f in filter(ordinarypath, files):
571 for f in filter(ordinarypath, files):
579 f = os.path.join(curdir, f)
572 f = os.path.join(curdir, f)
580 packagedata['mercurial'].append(f)
573 packagedata['mercurial'].append(f)
581
574
582 datafiles = []
575 datafiles = []
583 setupversion = version
576 setupversion = version
584 extra = {}
577 extra = {}
585
578
586 if py2exeloaded:
579 if py2exeloaded:
587 extra['console'] = [
580 extra['console'] = [
588 {'script':'hg',
581 {'script':'hg',
589 'copyright':'Copyright (C) 2005-2016 Matt Mackall and others',
582 'copyright':'Copyright (C) 2005-2016 Matt Mackall and others',
590 'product_version':version}]
583 'product_version':version}]
591 # sub command of 'build' because 'py2exe' does not handle sub_commands
584 # sub command of 'build' because 'py2exe' does not handle sub_commands
592 build.sub_commands.insert(0, ('build_hgextindex', None))
585 build.sub_commands.insert(0, ('build_hgextindex', None))
593 # put dlls in sub directory so that they won't pollute PATH
586 # put dlls in sub directory so that they won't pollute PATH
594 extra['zipfile'] = 'lib/library.zip'
587 extra['zipfile'] = 'lib/library.zip'
595
588
596 if os.name == 'nt':
589 if os.name == 'nt':
597 # Windows binary file versions for exe/dll files must have the
590 # Windows binary file versions for exe/dll files must have the
598 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
591 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
599 setupversion = version.split('+', 1)[0]
592 setupversion = version.split('+', 1)[0]
600
593
601 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
594 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
602 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
595 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
603 if version:
596 if version:
604 version = version[0]
597 version = version[0]
605 if sys.version_info[0] == 3:
598 if sys.version_info[0] == 3:
606 version = version.decode('utf-8')
599 version = version.decode('utf-8')
607 xcode4 = (version.startswith('Xcode') and
600 xcode4 = (version.startswith('Xcode') and
608 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
601 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
609 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
602 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
610 else:
603 else:
611 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
604 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
612 # installed, but instead with only command-line tools. Assume
605 # installed, but instead with only command-line tools. Assume
613 # that only happens on >= Lion, thus no PPC support.
606 # that only happens on >= Lion, thus no PPC support.
614 xcode4 = True
607 xcode4 = True
615 xcode51 = False
608 xcode51 = False
616
609
617 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
610 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
618 # distutils.sysconfig
611 # distutils.sysconfig
619 if xcode4:
612 if xcode4:
620 os.environ['ARCHFLAGS'] = ''
613 os.environ['ARCHFLAGS'] = ''
621
614
622 # XCode 5.1 changes clang such that it now fails to compile if the
615 # XCode 5.1 changes clang such that it now fails to compile if the
623 # -mno-fused-madd flag is passed, but the version of Python shipped with
616 # -mno-fused-madd flag is passed, but the version of Python shipped with
624 # OS X 10.9 Mavericks includes this flag. This causes problems in all
617 # OS X 10.9 Mavericks includes this flag. This causes problems in all
625 # C extension modules, and a bug has been filed upstream at
618 # C extension modules, and a bug has been filed upstream at
626 # http://bugs.python.org/issue21244. We also need to patch this here
619 # http://bugs.python.org/issue21244. We also need to patch this here
627 # so Mercurial can continue to compile in the meantime.
620 # so Mercurial can continue to compile in the meantime.
628 if xcode51:
621 if xcode51:
629 cflags = get_config_var('CFLAGS')
622 cflags = get_config_var('CFLAGS')
630 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
623 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
631 os.environ['CFLAGS'] = (
624 os.environ['CFLAGS'] = (
632 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
625 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
633
626
634 setup(name='mercurial',
627 setup(name='mercurial',
635 version=setupversion,
628 version=setupversion,
636 author='Matt Mackall and many others',
629 author='Matt Mackall and many others',
637 author_email='mercurial@selenic.com',
630 author_email='mercurial@selenic.com',
638 url='https://mercurial-scm.org/',
631 url='https://mercurial-scm.org/',
639 download_url='https://mercurial-scm.org/release/',
632 download_url='https://mercurial-scm.org/release/',
640 description=('Fast scalable distributed SCM (revision control, version '
633 description=('Fast scalable distributed SCM (revision control, version '
641 'control) system'),
634 'control) system'),
642 long_description=('Mercurial is a distributed SCM tool written in Python.'
635 long_description=('Mercurial is a distributed SCM tool written in Python.'
643 ' It is used by a number of large projects that require'
636 ' It is used by a number of large projects that require'
644 ' fast, reliable distributed revision control, such as '
637 ' fast, reliable distributed revision control, such as '
645 'Mozilla.'),
638 'Mozilla.'),
646 license='GNU GPLv2 or any later version',
639 license='GNU GPLv2 or any later version',
647 classifiers=[
640 classifiers=[
648 'Development Status :: 6 - Mature',
641 'Development Status :: 6 - Mature',
649 'Environment :: Console',
642 'Environment :: Console',
650 'Intended Audience :: Developers',
643 'Intended Audience :: Developers',
651 'Intended Audience :: System Administrators',
644 'Intended Audience :: System Administrators',
652 'License :: OSI Approved :: GNU General Public License (GPL)',
645 'License :: OSI Approved :: GNU General Public License (GPL)',
653 'Natural Language :: Danish',
646 'Natural Language :: Danish',
654 'Natural Language :: English',
647 'Natural Language :: English',
655 'Natural Language :: German',
648 'Natural Language :: German',
656 'Natural Language :: Italian',
649 'Natural Language :: Italian',
657 'Natural Language :: Japanese',
650 'Natural Language :: Japanese',
658 'Natural Language :: Portuguese (Brazilian)',
651 'Natural Language :: Portuguese (Brazilian)',
659 'Operating System :: Microsoft :: Windows',
652 'Operating System :: Microsoft :: Windows',
660 'Operating System :: OS Independent',
653 'Operating System :: OS Independent',
661 'Operating System :: POSIX',
654 'Operating System :: POSIX',
662 'Programming Language :: C',
655 'Programming Language :: C',
663 'Programming Language :: Python',
656 'Programming Language :: Python',
664 'Topic :: Software Development :: Version Control',
657 'Topic :: Software Development :: Version Control',
665 ],
658 ],
666 scripts=scripts,
659 scripts=scripts,
667 packages=packages,
660 packages=packages,
668 ext_modules=extmodules,
661 ext_modules=extmodules,
669 data_files=datafiles,
662 data_files=datafiles,
670 package_data=packagedata,
663 package_data=packagedata,
671 cmdclass=cmdclass,
664 cmdclass=cmdclass,
672 distclass=hgdist,
665 distclass=hgdist,
673 options={'py2exe': {'packages': ['hgext', 'email']},
666 options={'py2exe': {'packages': ['hgext', 'email']},
674 'bdist_mpkg': {'zipdist': False,
667 'bdist_mpkg': {'zipdist': False,
675 'license': 'COPYING',
668 'license': 'COPYING',
676 'readme': 'contrib/macosx/Readme.html',
669 'readme': 'contrib/macosx/Readme.html',
677 'welcome': 'contrib/macosx/Welcome.html',
670 'welcome': 'contrib/macosx/Welcome.html',
678 },
671 },
679 },
672 },
680 **extra)
673 **extra)
General Comments 0
You need to be logged in to leave comments. Login now