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