]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - setup.py
setup: remove custom Trial class inside our setup.py and use the setuptools_trial...
[tahoe-lafs/tahoe-lafs.git] / setup.py
1 #! /usr/bin/env python
2
3 # Allmydata Tahoe -- secure, distributed storage grid
4 #
5 # Copyright (C) 2008 Allmydata, Inc.
6 #
7 # This file is part of tahoe.
8 #
9 # See the docs/about.html file for licensing information.
10
11 import os, re, shutil, stat, subprocess, sys, zipfile
12
13 ##### sys.path management
14
15 def pylibdir(prefixdir):
16     pyver = "python%d.%d" % (sys.version_info[:2])
17     if sys.platform == "win32":
18         return os.path.join(prefixdir, "Lib", "site-packages")
19     else:
20         return os.path.join(prefixdir, "lib", pyver, "site-packages")
21
22 basedir = os.path.dirname(os.path.abspath(__file__))
23 supportlib = pylibdir(os.path.join(basedir, "support"))
24
25 for i in range(len(sys.argv)):
26     arg = sys.argv[i]
27     if arg == "build_tahoe":
28         del sys.argv[i]
29         sys.argv.extend(["develop", "--prefix=support", "--script-dir=support/bin"])
30
31 for i in range(len(sys.argv)):
32     arg = sys.argv[i]
33     prefixdir = None
34     if arg.startswith("--prefix="):
35         prefixdir = arg[len("--prefix="):]
36     if arg == "--prefix":
37         if len(sys.argv) > i+1:
38             prefixdir = sys.argv[i+1]
39
40     if prefixdir:
41         libdir = pylibdir(prefixdir)
42         try:
43             os.makedirs(libdir)
44         except EnvironmentError, le:
45             # Okay, maybe the dir was already there.
46             pass
47         sys.path.append(libdir)
48         pp = os.environ.get('PYTHONPATH','').split(os.pathsep)
49         pp.append(libdir)
50         os.environ['PYTHONPATH'] = os.pathsep.join(pp)
51
52     if arg.startswith("build"):
53         # chmod +x bin/tahoe
54         bin_tahoe = os.path.join("bin", "tahoe")
55         old_mode = stat.S_IMODE(os.stat(bin_tahoe)[stat.ST_MODE])
56         new_mode = old_mode | (stat.S_IXUSR | stat.S_IRUSR |
57                                stat.S_IXGRP | stat.S_IRGRP |
58                                stat.S_IXOTH | stat.S_IROTH )
59         os.chmod(bin_tahoe, new_mode)
60
61     if arg.startswith("install") or arg.startswith("develop"):
62         if sys.platform == "linux2":
63             # workaround for tahoe #229 / setuptools #17, on debian
64             sys.argv.extend(["--site-dirs", "/var/lib/python-support/python%d.%d" % (sys.version_info[:2])])
65         elif sys.platform == "darwin":
66             # this probably only applies to leopard 10.5, possibly only 10.5.5
67             sd = "/System/Library/Frameworks/Python.framework/Versions/%d.%d/Extras/lib/python" % (sys.version_info[:2])
68             sys.argv.extend(["--site-dirs", sd])
69
70 try:
71     from ez_setup import use_setuptools
72 except ImportError:
73     pass
74 else:
75     # This invokes our own customized version of ez_setup.py to make sure that
76     # setuptools >= v0.6c8 (a.k.a. v0.6-final) is installed.
77
78     # setuptools < v0.6c8 doesn't handle eggs which get installed into the CWD
79     # as a result of being transitively depended on in a setup_requires, but
80     # then are needed for the installed code to run, i.e. in an
81     # install_requires.
82     use_setuptools(download_delay=0, min_version="0.6c10dev")
83
84 from setuptools import find_packages, setup
85 from setuptools.command import sdist
86 from distutils.core import Command
87 from pkg_resources import require
88
89 # Make the dependency-version-requirement, which is used by the Makefile at
90 # build-time, also available to the app at runtime:
91 import shutil
92 shutil.copyfile("_auto_deps.py", os.path.join("src", "allmydata", "_auto_deps.py"))
93
94 trove_classifiers=[
95     "Development Status :: 5 - Production/Stable",
96     "Environment :: Console",
97     "Environment :: Web Environment",
98     "License :: OSI Approved :: GNU General Public License (GPL)",
99     "License :: DFSG approved",
100     "License :: Other/Proprietary License",
101     "Intended Audience :: Developers",
102     "Intended Audience :: End Users/Desktop",
103     "Intended Audience :: System Administrators",
104     "Operating System :: Microsoft",
105     "Operating System :: Microsoft :: Windows",
106     "Operating System :: Microsoft :: Windows :: Windows NT/2000",
107     "Operating System :: Unix",
108     "Operating System :: POSIX :: Linux",
109     "Operating System :: POSIX",
110     "Operating System :: MacOS :: MacOS X",
111     "Operating System :: OS Independent",
112     "Natural Language :: English",
113     "Programming Language :: C",
114     "Programming Language :: Python",
115     "Programming Language :: Python :: 2",
116     "Programming Language :: Python :: 2.4",
117     "Programming Language :: Python :: 2.5",
118     "Topic :: Utilities",
119     "Topic :: System :: Systems Administration",
120     "Topic :: System :: Filesystems",
121     "Topic :: System :: Distributed Computing",
122     "Topic :: Software Development :: Libraries",
123     "Topic :: Communications :: Usenet News",
124     "Topic :: System :: Archiving :: Backup",
125     "Topic :: System :: Archiving :: Mirroring",
126     "Topic :: System :: Archiving",
127     ]
128
129
130 VERSIONFILE = "src/allmydata/_version.py"
131 verstr = "unknown"
132 try:
133     verstrline = open(VERSIONFILE, "rt").read()
134 except EnvironmentError:
135     pass # Okay, there is no version file.
136 else:
137     VSRE = r"^verstr = ['\"]([^'\"]*)['\"]"
138     mo = re.search(VSRE, verstrline, re.M)
139     if mo:
140         verstr = mo.group(1)
141     else:
142         print "unable to find version in %s" % (VERSIONFILE,)
143         raise RuntimeError("if %s.py exists, it is required to be well-formed" % (VERSIONFILE,))
144
145 LONG_DESCRIPTION=\
146 """Welcome to the Tahoe project, a secure, decentralized, fault-tolerant
147 filesystem.  All of the source code is available under a Free Software, Open
148 Source licence.
149
150 This filesystem is encrypted and spread over multiple peers in such a way that
151 it remains available even when some of the peers are unavailable,
152 malfunctioning, or malicious."""
153
154
155 setup_requires = []
156
157 # Nevow requires Twisted to setup, but doesn't declare that requirement in a way that enables
158 # setuptools to satisfy that requirement before Nevow's setup.py tried to "import twisted".
159 setup_requires.extend(['Twisted >= 2.4.0', 'setuptools_trial'])
160
161 # darcsver is needed only if you want "./setup.py darcsver" to write a new
162 # version stamp in src/allmydata/_version.py, with a version number derived from
163 # darcs history.
164 # http://pypi.python.org/pypi/darcsver
165 if 'darcsver' in sys.argv[1:]:
166     setup_requires.append('darcsver >= 1.1.5')
167
168 # setuptools_trial is needed only if you want "./setup.py trial" to execute the tests.
169 # http://pypi.python.org/pypi/setuptools_trial
170 if 'trial' in sys.argv[1:]:
171     setup_requires.append('setuptools_trial >= 0.2')
172
173 # setuptools_darcs is required to produce complete distributions (such as with
174 # "sdist" or "bdist_egg"), unless there is a PKG-INFO file present which shows
175 # that this is itself a source distribution.
176 # http://pypi.python.org/pypi/setuptools_darcs
177 if not os.path.exists('PKG-INFO'):
178     setup_requires.append('setuptools_darcs >= 1.1.0')
179
180 class ShowSupportLib(Command):
181     user_options = []
182     def initialize_options(self):
183         pass
184     def finalize_options(self):
185         pass
186     def run(self):
187         # TODO: --quiet suppresses the 'running show_supportlib' message.
188         # Find a way to do this all the time.
189         print supportlib # TODO windowsy
190
191 class ShowPythonPath(Command):
192     user_options = []
193     def initialize_options(self):
194         pass
195     def finalize_options(self):
196         pass
197     def run(self):
198         # TODO: --quiet suppresses the 'running show_supportlib' message.
199         # Find a way to do this all the time.
200         print "PYTHONPATH=%s" % os.environ["PYTHONPATH"]
201
202 class RunWithPythonPath(Command):
203     description = "Run a subcommand with PYTHONPATH set appropriately"
204
205     user_options = [ ("python", "p",
206                       "Treat command string as arguments to a python executable"),
207                      ("command=", "c", "Command to be run"),
208                      ("directory=", "d", "Directory to run the command in"),
209                      ]
210     boolean_options = ["python"]
211
212     def initialize_options(self):
213         self.command = None
214         self.python = False
215         self.directory = None
216     def finalize_options(self):
217         pass
218     def run(self):
219         # os.environ['PYTHONPATH'] is already set by add_tahoe_paths, so we
220         # just need to exec() their command. We must require the command to
221         # be safe to split on whitespace, and have --python and --directory
222         # to make it easier to achieve this.
223         command = []
224         if self.python:
225             command.append(sys.executable)
226         if self.command:
227             command.extend(self.command.split())
228         if not command:
229             raise RuntimeError("The --command argument is mandatory")
230         if self.directory:
231             os.chdir(self.directory)
232         if self.verbose:
233             print "command =", " ".join(command)
234         rc = subprocess.call(command)
235         sys.exit(rc)
236
237 class CheckAutoDeps(Command):
238     user_options = []
239     def initialize_options(self):
240         pass
241     def finalize_options(self):
242         pass
243     def run(self):
244         import _auto_deps
245         _auto_deps.require_auto_deps()
246
247
248 class BuildTahoe(Command):
249     user_options = []
250     def initialize_options(self):
251         pass
252     def finalize_options(self):
253         pass
254     def run(self):
255         # On Windows, create the 'tahoe-script.py' file based on the 'tahoe'
256         # executable script under the 'bin' directory so that the tahoe.exe
257         # will work correctly.  The 'tahoe-script.py' file is exactly the same
258         # as the 'tahoe' script except that we need to update the she-bang
259         # line.  The tahoe.exe will be copied from the setuptools egg's cli.exe
260         # and this will work from a zip-safe and non-zip-safe setuptools egg.
261         if sys.platform == "win32":
262             setuptools_egg = require("setuptools")[0].location
263             if os.path.isfile(setuptools_egg):
264                 z = zipfile.ZipFile(setuptools_egg, 'r')
265                 for filename in z.namelist():
266                     if 'cli.exe' in filename:
267                         cli_exe = z.read(filename)
268             else:
269                 cli_exe = os.path.join(setuptools_egg, 'setuptools', 'cli.exe')
270             tahoe_exe = os.path.join("bin", "tahoe.exe")
271             if os.path.isfile(setuptools_egg):
272                 f = open(tahoe_exe, 'wb')
273                 f.write(cli_exe)
274                 f.close()
275             else:
276                 shutil.copy(cli_exe, tahoe_exe)
277             bin_tahoe = os.path.join("bin", "tahoe")
278             f = open(bin_tahoe, "r")
279             script_lines = f.readlines()
280             f.close()
281             script_lines[0] = "#!%s\n" % sys.executable
282             tahoe_script = os.path.join("bin", "tahoe-script.py")
283             f = open(tahoe_script, "w")
284             for line in script_lines:
285                 f.write(line)
286             f.close()
287
288         command = [sys.executable, "setup.py", "develop", "--prefix", "support"]
289         print "Command:", " ".join(command)
290         rc = subprocess.call(command)
291         if rc < 0:
292             print >>sys.stderr, "'setup.py develop' terminated by signal", -rc
293             sys.exit(1)
294         elif rc > 0:
295             print >>sys.stderr, "'setup.py develop' exited with rc", rc
296             sys.exit(rc)
297
298 class MySdist(sdist.sdist):
299     """ A hook in the sdist command so that we can determine whether this the
300     tarball should be 'SUMO' or not, i.e. whether or not to include the
301     external dependency tarballs. Note that we always include
302     misc/dependencies/* in the tarball; --sumo controls whether tahoe-deps/*
303     is included as well.
304     """
305
306     user_options = sdist.sdist.user_options + \
307         [('sumo', 's',
308           "create a 'sumo' sdist which includes the contents of tahoe-deps/*"),
309          ]
310     boolean_options = ['sumo']
311
312     def initialize_options(self):
313         sdist.sdist.initialize_options(self)
314         self.sumo = False
315
316     def make_distribution(self):
317         # add our extra files to the list just before building the
318         # tarball/zipfile. We override make_distribution() instead of run()
319         # because setuptools.command.sdist.run() does not lend itself to
320         # easy/robust subclassing (the code we need to add goes right smack
321         # in the middle of a 12-line method). If this were the distutils
322         # version, we'd override get_file_list().
323
324         if self.sumo:
325             # If '--sumo' was specified, include tahoe-deps/* in the sdist.
326             # We assume that the user has fetched the tahoe-deps.tar.gz
327             # tarball and unpacked it already.
328             self.filelist.extend([os.path.join("tahoe-deps", fn)
329                                   for fn in os.listdir("tahoe-deps")])
330             # In addition, we want the tarball/zipfile to have -SUMO in the
331             # name, and the unpacked directory to have -SUMO too. The easiest
332             # way to do this is to patch self.distribution and override the
333             # get_fullname() method. (an alternative is to modify
334             # self.distribution.metadata.version, but that also affects the
335             # contents of PKG-INFO).
336             fullname = self.distribution.get_fullname()
337             def get_fullname():
338                 return fullname + "-SUMO"
339             self.distribution.get_fullname = get_fullname
340
341         return sdist.sdist.make_distribution(self)
342
343 # Tahoe's dependencies are managed by the find_links= entry in setup.cfg and
344 # the _auto_deps.install_requires list, which is used in the call to setup()
345 # at the end of this file
346 from _auto_deps import install_requires
347
348 setup(name='allmydata-tahoe',
349       version=verstr,
350       description='secure, decentralized, fault-tolerant filesystem',
351       long_description=LONG_DESCRIPTION,
352       author='the allmydata.org Tahoe project',
353       author_email='tahoe-dev@allmydata.org',
354       url='http://allmydata.org/',
355       license='GNU GPL',
356       cmdclass={"show_supportlib": ShowSupportLib,
357                 "show_pythonpath": ShowPythonPath,
358                 "run_with_pythonpath": RunWithPythonPath,
359                 "check_auto_deps": CheckAutoDeps,
360                 "build_tahoe": BuildTahoe,
361                 "sdist": MySdist,
362                 },
363       package_dir = {'':'src'},
364       packages=find_packages("src"),
365       classifiers=trove_classifiers,
366       test_suite="allmydata.test",
367       install_requires=install_requires,
368       include_package_data=True,
369       setup_requires=setup_requires,
370       entry_points = { 'console_scripts': [ 'tahoe = allmydata.scripts.runner:run' ] },
371       zip_safe=False, # We prefer unzipped for easier access.
372       )