3 # This is the mercurial setup script.
5 # 'python setup.py install', or
6 # 'python setup.py --help' for more options
9 if not hasattr(sys, 'version_info') or sys.version_info < (2, 4, 0, 'final'):
10 raise SystemExit("Mercurial requires Python 2.4 or later.")
12 # Solaris Python packaging brain damage
21 "Couldn't import standard hashlib (incomplete Python install).")
27 "Couldn't import standard zlib (incomplete Python install).")
29 import os, subprocess, time
32 from distutils.core import setup, Extension
33 from distutils.dist import Distribution
34 from distutils.command.install_data import install_data
35 from distutils.command.build import build
36 from distutils.command.build_py import build_py
37 from distutils.spawn import spawn, find_executable
38 from distutils.ccompiler import new_compiler
43 scripts.append('contrib/win32/hg.bat')
45 # simplified version of distutils.ccompiler.CCompiler.has_function
46 # that actually removes its temporary files.
47 def has_function(cc, funcname):
48 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
49 devnull = oldstderr = None
52 fname = os.path.join(tmpdir, 'funcname.c')
54 f.write('int main(void) {\n')
55 f.write(' %s();\n' % funcname)
58 # Redirect stderr to /dev/null to hide any error messages
60 # This will have to be changed if we ever have to check
61 # for a function on Windows.
62 devnull = open('/dev/null', 'w')
63 oldstderr = os.dup(sys.stderr.fileno())
64 os.dup2(devnull.fileno(), sys.stderr.fileno())
65 objects = cc.compile([fname], output_dir=tmpdir)
66 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
71 if oldstderr is not None:
72 os.dup2(oldstderr, sys.stderr.fileno())
73 if devnull is not None:
77 # py2exe needs to be installed to work
81 # Help py2exe to find win32com.shell
85 for p in win32com.__path__[1:]: # Take the path to win32comext
86 modulefinder.AddPackagePath("win32com", p)
90 for p in m.__path__[1:]:
91 modulefinder.AddPackagePath(pn, p)
95 extra['console'] = ['hg']
102 if os.path.isdir('.hg'):
103 # Execute hg out of this directory with a custom environment which
104 # includes the pure Python modules in mercurial/pure. We also take
105 # care to not use any hgrc files and do no localization.
106 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
107 env = {'PYTHONPATH': os.pathsep.join(pypath),
110 if 'SystemRoot' in os.environ:
111 # Copy SystemRoot into the custom environment for Python 2.6
112 # under Windows. Otherwise, the subprocess will fail with
113 # error 0xc0150004. See: http://bugs.python.org/issue3440
114 env['SystemRoot'] = os.environ['SystemRoot']
115 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
117 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
118 stderr=subprocess.PIPE, env=env)
119 out, err = p.communicate()
121 # If root is executing setup.py, but the repository is owned by
122 # another user (as in "sudo python setup.py install") we will get
123 # trust warnings since the .hg/hgrc file is untrusted. That is
124 # fine, we don't want to load it anyway.
125 err = [e for e in err.splitlines()
126 if not e.startswith('Not trusting file')]
128 sys.stderr.write('warning: could not establish Mercurial '
129 'version:\n%s\n' % '\n'.join(err))
132 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
135 version = l[-1] # latest tag or revision number
136 if version.endswith('+'):
137 version += time.strftime('%Y%m%d')
138 elif os.path.exists('.hg_archival.txt'):
139 hgarchival = open('.hg_archival.txt')
140 for line in hgarchival:
141 if line.startswith('node:'):
142 version = line.split(':')[1].strip()[:12]
146 f = open("mercurial/__version__.py", "w")
147 f.write('# this file is autogenerated by setup.py\n')
148 f.write('version = "%s"\n' % version)
153 from mercurial import __version__
154 version = __version__.version
158 class install_package_data(install_data):
159 def finalize_options(self):
160 self.set_undefined_options('install',
161 ('install_lib', 'install_dir'))
162 install_data.finalize_options(self)
164 class build_mo(build):
166 description = "build translations (.mo files)"
169 if not find_executable('msgfmt'):
170 self.warn("could not find msgfmt executable, no translations "
175 if not os.path.isdir(podir):
176 self.warn("could not find %s/ directory" % podir)
180 for po in os.listdir(podir):
181 if not po.endswith('.po'):
183 pofile = join(podir, po)
184 modir = join('locale', po[:-3], 'LC_MESSAGES')
185 mofile = join(modir, 'hg.mo')
186 cmd = ['msgfmt', '-v', '-o', mofile, pofile]
187 if sys.platform != 'sunos5':
188 # msgfmt on Solaris does not know about -c
191 self.make_file([pofile], mofile, spawn, (cmd,))
192 self.distribution.data_files.append((join('mercurial', modir),
195 build.sub_commands.append(('build_mo', None))
197 Distribution.pure = 0
198 Distribution.global_options.append(('pure', None, "use pure (slow) Python "
199 "code instead of C extensions"))
201 class hg_build_py(build_py):
203 def finalize_options(self):
204 build_py.finalize_options(self)
206 if self.distribution.pure:
207 if self.py_modules is None:
209 for ext in self.distribution.ext_modules:
210 if ext.name.startswith("mercurial."):
211 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
212 self.distribution.ext_modules = []
214 def find_modules(self):
215 modules = build_py.find_modules(self)
216 for module in modules:
217 if module[0] == "mercurial.pure":
218 if module[1] != "__init__":
219 yield ("mercurial", module[1], module[2])
223 cmdclass = {'install_data': install_package_data,
224 'build_mo': build_mo,
225 'build_py': hg_build_py}
228 Extension('mercurial.base85', ['mercurial/base85.c']),
229 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
230 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
231 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
232 Extension('mercurial.parsers', ['mercurial/parsers.c']),
233 Extension('mercurial.osutil', ['mercurial/osutil.c']),
236 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert',
237 'hgext.highlight', 'hgext.zeroconf', ]
239 if sys.platform == 'linux2' and os.uname()[2] > '2.6':
240 # The inotify extension is only usable with Linux 2.6 kernels.
241 # You also need a reasonably recent C library.
243 if has_function(cc, 'inotify_add_watch'):
244 ext_modules.append(Extension('hgext.inotify.linux._inotify',
245 ['hgext/inotify/linux/_inotify.c']))
246 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
249 for root in ('templates', 'i18n'):
250 for dir, dirs, files in os.walk(root):
251 dirs[:] = [x for x in dirs if not x.startswith('.')]
252 files = [x for x in files if not x.startswith('.')]
253 datafiles.append((os.path.join('mercurial', dir),
254 [os.path.join(dir, file_) for file_ in files]))
256 setup(name='mercurial',
258 author='Matt Mackall',
259 author_email='mpm@selenic.com',
260 url='http://mercurial.selenic.com/',
261 description='Scalable distributed SCM',
265 ext_modules=ext_modules,
266 data_files=datafiles,
268 options=dict(py2exe=dict(packages=['hgext', 'email']),
269 bdist_mpkg=dict(zipdist=True,
271 readme='contrib/macosx/Readme.html',
272 welcome='contrib/macosx/Welcome.html')),