]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - setup.py
setup: attempt to remove the custom setuptools-ish logic in setup.py -- the result...
[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, sys, stat, subprocess
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
88 import pkg_resources
89 pkg_resources.require('setuptools_trial')
90 from setuptools_trial.setuptools_trial import TrialTest
91
92 # Make the dependency-version-requirement, which is used by the Makefile at
93 # build-time, also available to the app at runtime:
94 import shutil
95 shutil.copyfile("_auto_deps.py", os.path.join("src", "allmydata", "_auto_deps.py"))
96
97 trove_classifiers=[
98     "Development Status :: 5 - Production/Stable",
99     "Environment :: Console",
100     "Environment :: Web Environment",
101     "License :: OSI Approved :: GNU General Public License (GPL)",
102     "License :: DFSG approved",
103     "License :: Other/Proprietary License",
104     "Intended Audience :: Developers",
105     "Intended Audience :: End Users/Desktop",
106     "Intended Audience :: System Administrators",
107     "Operating System :: Microsoft",
108     "Operating System :: Microsoft :: Windows",
109     "Operating System :: Microsoft :: Windows :: Windows NT/2000",
110     "Operating System :: Unix",
111     "Operating System :: POSIX :: Linux",
112     "Operating System :: POSIX",
113     "Operating System :: MacOS :: MacOS X",
114     "Operating System :: OS Independent",
115     "Natural Language :: English",
116     "Programming Language :: C",
117     "Programming Language :: Python",
118     "Programming Language :: Python :: 2",
119     "Programming Language :: Python :: 2.4",
120     "Programming Language :: Python :: 2.5",
121     "Topic :: Utilities",
122     "Topic :: System :: Systems Administration",
123     "Topic :: System :: Filesystems",
124     "Topic :: System :: Distributed Computing",
125     "Topic :: Software Development :: Libraries",
126     "Topic :: Communications :: Usenet News",
127     "Topic :: System :: Archiving :: Backup",
128     "Topic :: System :: Archiving :: Mirroring",
129     "Topic :: System :: Archiving",
130     ]
131
132
133 VERSIONFILE = "src/allmydata/_version.py"
134 verstr = "unknown"
135 try:
136     verstrline = open(VERSIONFILE, "rt").read()
137 except EnvironmentError:
138     pass # Okay, there is no version file.
139 else:
140     VSRE = r"^verstr = ['\"]([^'\"]*)['\"]"
141     mo = re.search(VSRE, verstrline, re.M)
142     if mo:
143         verstr = mo.group(1)
144     else:
145         print "unable to find version in %s" % (VERSIONFILE,)
146         raise RuntimeError("if %s.py exists, it is required to be well-formed" % (VERSIONFILE,))
147
148 LONG_DESCRIPTION=\
149 """Welcome to the Tahoe project, a secure, decentralized, fault-tolerant
150 filesystem.  All of the source code is available under a Free Software, Open
151 Source licence.
152
153 This filesystem is encrypted and spread over multiple peers in such a way that
154 it remains available even when some of the peers are unavailable,
155 malfunctioning, or malicious."""
156
157
158 setup_requires = []
159
160 # Nevow requires Twisted to setup, but doesn't declare that requirement in a way that enables
161 # setuptools to satisfy that requirement before Nevow's setup.py tried to "import twisted".
162 setup_requires.extend(['Twisted >= 2.4.0', 'setuptools_trial'])
163
164 # darcsver is needed only if you want "./setup.py darcsver" to write a new
165 # version stamp in src/allmydata/_version.py, with a version number derived from
166 # darcs history.
167 # http://pypi.python.org/pypi/darcsver
168 if 'darcsver' in sys.argv[1:]:
169     setup_requires.append('darcsver >= 1.1.5')
170
171 # setuptools_trial is needed only if you want "./setup.py trial" to execute the tests.
172 # http://pypi.python.org/pypi/setuptools_trial
173 if 'trial' in sys.argv[1:]:
174     setup_requires.append('setuptools_trial >= 0.2')
175
176 # setuptools_darcs is required to produce complete distributions (such as with
177 # "sdist" or "bdist_egg"), unless there is a PKG-INFO file present which shows
178 # that this is itself a source distribution.
179 # http://pypi.python.org/pypi/setuptools_darcs
180 if not os.path.exists('PKG-INFO'):
181     setup_requires.append('setuptools_darcs >= 1.1.0')
182
183 class ShowSupportLib(Command):
184     user_options = []
185     def initialize_options(self):
186         pass
187     def finalize_options(self):
188         pass
189     def run(self):
190         # TODO: --quiet suppresses the 'running show_supportlib' message.
191         # Find a way to do this all the time.
192         print supportlib # TODO windowsy
193
194 class ShowPythonPath(Command):
195     user_options = []
196     def initialize_options(self):
197         pass
198     def finalize_options(self):
199         pass
200     def run(self):
201         # TODO: --quiet suppresses the 'running show_supportlib' message.
202         # Find a way to do this all the time.
203         print "PYTHONPATH=%s" % os.environ["PYTHONPATH"]
204
205 class RunWithPythonPath(Command):
206     description = "Run a subcommand with PYTHONPATH set appropriately"
207
208     user_options = [ ("python", "p",
209                       "Treat command string as arguments to a python executable"),
210                      ("command=", "c", "Command to be run"),
211                      ("directory=", "d", "Directory to run the command in"),
212                      ]
213     boolean_options = ["python"]
214
215     def initialize_options(self):
216         self.command = None
217         self.python = False
218         self.directory = None
219     def finalize_options(self):
220         pass
221     def run(self):
222         # os.environ['PYTHONPATH'] is already set by add_tahoe_paths, so we
223         # just need to exec() their command. We must require the command to
224         # be safe to split on whitespace, and have --python and --directory
225         # to make it easier to achieve this.
226         command = []
227         if self.python:
228             command.append(sys.executable)
229         if self.command:
230             command.extend(self.command.split())
231         if not command:
232             raise RuntimeError("The --command argument is mandatory")
233         if self.directory:
234             os.chdir(self.directory)
235         if self.verbose:
236             print "command =", " ".join(command)
237         rc = subprocess.call(command)
238         sys.exit(rc)
239
240 class CheckAutoDeps(Command):
241     user_options = []
242     def initialize_options(self):
243         pass
244     def finalize_options(self):
245         pass
246     def run(self):
247         import _auto_deps
248         _auto_deps.require_auto_deps()
249
250
251 class BuildTahoe(Command):
252     user_options = []
253     def initialize_options(self):
254         pass
255     def finalize_options(self):
256         pass
257     def run(self):
258         command = [sys.executable, "setup.py", "develop", "--prefix", "support"]
259         print "Command:", " ".join(command)
260         rc = subprocess.call(command)
261         if rc < 0:
262             print >>sys.stderr, "'setup.py develop' terminated by signal", -rc
263             sys.exit(1)
264         elif rc > 0:
265             print >>sys.stderr, "'setup.py develop' exited with rc", rc
266             sys.exit(rc)
267
268 class Trial(TrialTest):
269     # Custom sub-class of the TrialTest class from the setuptools_trial
270     # plugin so that we can ensure certain options are set by default.
271     #
272     # Examples:
273     #  setup.py trial    # run all tests
274     #  setup.py trial -a allmydata.test.test_util   # run some tests
275     #  setup.py trial -a '--reporter=text allmydata.test.test_util' #other args
276
277
278     def initialize_options(self):
279         TrialTest.initialize_options(self)
280
281         # We want to set the reactor to 'poll', because of bug #402
282         # (twisted bug #3218).
283         if sys.platform in ("linux2", "cygwin"):
284             # poll on linux2 to avoid #402 problems with select
285             # poll on cygwin since selectreactor runs out of fds
286             self.reactor = "poll"
287
288
289 class MySdist(sdist.sdist):
290     """ A hook in the sdist command so that we can determine whether this the
291     tarball should be 'SUMO' or not, i.e. whether or not to include the
292     external dependency tarballs. Note that we always include
293     misc/dependencies/* in the tarball; --sumo controls whether tahoe-deps/*
294     is included as well.
295     """
296
297     user_options = sdist.sdist.user_options + \
298         [('sumo', 's',
299           "create a 'sumo' sdist which includes the contents of tahoe-deps/*"),
300          ]
301     boolean_options = ['sumo']
302
303     def initialize_options(self):
304         sdist.sdist.initialize_options(self)
305         self.sumo = False
306
307     def make_distribution(self):
308         # add our extra files to the list just before building the
309         # tarball/zipfile. We override make_distribution() instead of run()
310         # because setuptools.command.sdist.run() does not lend itself to
311         # easy/robust subclassing (the code we need to add goes right smack
312         # in the middle of a 12-line method). If this were the distutils
313         # version, we'd override get_file_list().
314
315         if self.sumo:
316             # If '--sumo' was specified, include tahoe-deps/* in the sdist.
317             # We assume that the user has fetched the tahoe-deps.tar.gz
318             # tarball and unpacked it already.
319             self.filelist.extend([os.path.join("tahoe-deps", fn)
320                                   for fn in os.listdir("tahoe-deps")])
321             # In addition, we want the tarball/zipfile to have -SUMO in the
322             # name, and the unpacked directory to have -SUMO too. The easiest
323             # way to do this is to patch self.distribution and override the
324             # get_fullname() method. (an alternative is to modify
325             # self.distribution.metadata.version, but that also affects the
326             # contents of PKG-INFO).
327             fullname = self.distribution.get_fullname()
328             def get_fullname():
329                 return fullname + "-SUMO"
330             self.distribution.get_fullname = get_fullname
331
332         return sdist.sdist.make_distribution(self)
333
334 # Tahoe's dependencies are managed by the find_links= entry in setup.cfg and
335 # the _auto_deps.install_requires list, which is used in the call to setup()
336 # at the end of this file
337 from _auto_deps import install_requires
338
339 setup(name='allmydata-tahoe',
340       version=verstr,
341       description='secure, decentralized, fault-tolerant filesystem',
342       long_description=LONG_DESCRIPTION,
343       author='the allmydata.org Tahoe project',
344       author_email='tahoe-dev@allmydata.org',
345       url='http://allmydata.org/',
346       license='GNU GPL',
347       cmdclass={"show_supportlib": ShowSupportLib,
348                 "show_pythonpath": ShowPythonPath,
349                 "run_with_pythonpath": RunWithPythonPath,
350                 "check_auto_deps": CheckAutoDeps,
351                 "build_tahoe": BuildTahoe,
352                 "trial": Trial,
353                 "sdist": MySdist,
354                 },
355       package_dir = {'':'src'},
356       packages=find_packages("src"),
357       classifiers=trove_classifiers,
358       test_suite="allmydata.test",
359       install_requires=install_requires,
360       include_package_data=True,
361       setup_requires=setup_requires,
362       entry_points = { 'console_scripts': [ 'tahoe = allmydata.scripts.runner:run' ] },
363       zip_safe=False, # We prefer unzipped for easier access.
364       )