]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - setup.py
setup: upgrade bundled zetuptoolz to zetuptoolz-0.6c15dev and make it unpacked and...
[tahoe-lafs/tahoe-lafs.git] / setup.py
1 #! /usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 # Tahoe-LAFS -- secure, distributed storage grid
5 #
6 # Copyright © 2008-2010 Allmydata, Inc.
7 #
8 # This file is part of Tahoe-LAFS.
9 #
10 # See the docs/about.html file for licensing information.
11
12 import glob, os, shutil, stat, subprocess, sys, zipfile, re
13
14 ##### sys.path management
15
16 def pylibdir(prefixdir):
17     pyver = "python%d.%d" % (sys.version_info[:2])
18     if sys.platform == "win32":
19         return os.path.join(prefixdir, "Lib", "site-packages")
20     else:
21         return os.path.join(prefixdir, "lib", pyver, "site-packages")
22
23 basedir = os.path.dirname(os.path.abspath(__file__))
24 supportlib = pylibdir(os.path.join(basedir, "support"))
25
26 # locate our version number
27
28 def read_version_py(infname):
29     try:
30         verstrline = open(infname, "rt").read()
31     except EnvironmentError:
32         return None
33     else:
34         VSRE = r"^verstr = ['\"]([^'\"]*)['\"]"
35         mo = re.search(VSRE, verstrline, re.M)
36         if mo:
37             return mo.group(1)
38
39 version = read_version_py("src/allmydata/_version.py")
40
41 egg = os.path.realpath(glob.glob('setuptools-*.egg')[0])
42 sys.path.insert(0, egg)
43 import setuptools; setuptools.bootstrap_install_from = egg
44
45 from setuptools import find_packages, setup
46 from setuptools.command import sdist
47 from setuptools import Command
48
49 # Make the dependency-version-requirement, which is used by the Makefile at
50 # build-time, also available to the app at runtime:
51 shutil.copyfile("_auto_deps.py",
52                 os.path.join("src", "allmydata", "_auto_deps.py"))
53
54 trove_classifiers=[
55     "Development Status :: 5 - Production/Stable",
56     "Environment :: Console",
57     "Environment :: Web Environment",
58     "License :: OSI Approved :: GNU General Public License (GPL)",
59     "License :: DFSG approved",
60     "License :: Other/Proprietary License",
61     "Intended Audience :: Developers",
62     "Intended Audience :: End Users/Desktop",
63     "Intended Audience :: System Administrators",
64     "Operating System :: Microsoft",
65     "Operating System :: Microsoft :: Windows",
66     "Operating System :: Microsoft :: Windows :: Windows NT/2000",
67     "Operating System :: Unix",
68     "Operating System :: POSIX :: Linux",
69     "Operating System :: POSIX",
70     "Operating System :: MacOS :: MacOS X",
71     "Operating System :: OS Independent",
72     "Natural Language :: English",
73     "Programming Language :: C",
74     "Programming Language :: Python",
75     "Programming Language :: Python :: 2",
76     "Programming Language :: Python :: 2.4",
77     "Programming Language :: Python :: 2.5",
78     "Programming Language :: Python :: 2.6",
79     "Topic :: Utilities",
80     "Topic :: System :: Systems Administration",
81     "Topic :: System :: Filesystems",
82     "Topic :: System :: Distributed Computing",
83     "Topic :: Software Development :: Libraries",
84     "Topic :: Communications :: Usenet News",
85     "Topic :: System :: Archiving :: Backup",
86     "Topic :: System :: Archiving :: Mirroring",
87     "Topic :: System :: Archiving",
88     ]
89
90
91 setup_requires = []
92
93 # The darcsver command from the darcsver plugin is needed to initialize the
94 # distribution's .version attribute correctly. (It does this either by
95 # examining darcs history, or if that fails by reading the
96 # src/allmydata/_version.py file). darcsver will also write a new version
97 # stamp in src/allmydata/_version.py, with a version number derived from
98 # darcs history. Note that the setup.cfg file has an "[aliases]" section
99 # which enumerates commands that you might run and specifies that it will run
100 # darcsver before each one. If you add different commands (or if I forgot
101 # some that are already in use), you may need to add it to setup.cfg and
102 # configure it to run darcsver before your command, if you want the version
103 # number to be correct when that command runs.
104 # http://pypi.python.org/pypi/darcsver
105 setup_requires.append('darcsver >= 1.2.0')
106
107 # Nevow requires Twisted to setup, but doesn't declare that requirement in a
108 # way that enables setuptools to satisfy that requirement before Nevow's
109 # setup.py tried to "import twisted". Fortunately we require setuptools_trial
110 # to setup and setuptools_trial requires Twisted to install, so hopefully
111 # everything will work out until the Nevow issue is fixed:
112 # http://divmod.org/trac/ticket/2629 setuptools_trial is needed if you want
113 # "./setup.py trial" or "./setup.py test" to execute the tests (and in order
114 # to make sure Twisted is installed early enough -- see the paragraph above).
115 # http://pypi.python.org/pypi/setuptools_trial
116 setup_requires.extend(['setuptools_trial >= 0.5'])
117
118 # setuptools_darcs is required to produce complete distributions (such as
119 # with "sdist" or "bdist_egg") (unless there is a PKG-INFO file present which
120 # shows that this is itself a source distribution). For simplicity, and
121 # because there is some unknown error with setuptools_darcs when building and
122 # testing tahoe all in one python command on some platforms, we always add it
123 # to setup_requires. http://pypi.python.org/pypi/setuptools_darcs
124 setup_requires.append('setuptools_darcs >= 1.1.0')
125
126 # trialcoverage is required if you want the "trial" unit test runner to have a
127 # "--reporter=bwverbose-coverage" option which produces code-coverage results.
128 if "--reporter=bwverbose-coverage" in sys.argv:
129     setup_requires.append('trialcoverage >= 0.3.10')
130
131 # stdeb is required to produce Debian files with the "sdist_dsc" command.
132 if "sdist_dsc" in sys.argv:
133     setup_requires.append('stdeb >= 0.3')
134
135 class ShowSupportLib(Command):
136     user_options = []
137     def initialize_options(self):
138         pass
139     def finalize_options(self):
140         pass
141     def run(self):
142         # TODO: --quiet suppresses the 'running show_supportlib' message.
143         # Find a way to do this all the time.
144         print supportlib # TODO windowsy
145
146 class ShowPythonPath(Command):
147     user_options = []
148     def initialize_options(self):
149         pass
150     def finalize_options(self):
151         pass
152     def run(self):
153         # TODO: --quiet suppresses the 'running show_supportlib' message.
154         # Find a way to do this all the time.
155         print "PYTHONPATH=%s" % os.environ.get("PYTHONPATH", '')
156
157 class RunWithPythonPath(Command):
158     description = "Run a subcommand with PYTHONPATH set appropriately"
159
160     user_options = [ ("python", "p",
161                       "Treat command string as arguments to a python executable"),
162                      ("command=", "c", "Command to be run"),
163                      ("directory=", "d", "Directory to run the command in"),
164                      ]
165     boolean_options = ["python"]
166
167     def initialize_options(self):
168         self.command = None
169         self.python = False
170         self.directory = None
171     def finalize_options(self):
172         pass
173     def run(self):
174         oldpp = os.environ.get("PYTHONPATH", "").split(os.pathsep)
175         if oldpp == [""]:
176             # grr silly split() behavior
177             oldpp = []
178         os.environ['PYTHONPATH'] = os.pathsep.join(oldpp + [supportlib,])
179
180         # We must require the command to be safe to split on
181         # whitespace, and have --python and --directory to make it
182         # easier to achieve this.
183
184         command = []
185         if self.python:
186             command.append(sys.executable)
187         if self.command:
188             command.extend(self.command.split())
189         if not command:
190             raise RuntimeError("The --command argument is mandatory")
191         if self.directory:
192             os.chdir(self.directory)
193         if self.verbose:
194             print "command =", " ".join(command)
195         rc = subprocess.call(command)
196         sys.exit(rc)
197
198 class TestMacDiskImage(Command):
199     user_options = []
200     def initialize_options(self):
201         pass
202     def finalize_options(self):
203         pass
204     def run(self):
205         import sys
206         sys.path.append('misc')
207         import test_mac_diskimage
208         return test_mac_diskimage.test_mac_diskimage('Allmydata', version=self.distribution.metadata.version)
209
210 class CheckAutoDeps(Command):
211     user_options = []
212     def initialize_options(self):
213         pass
214     def finalize_options(self):
215         pass
216     def run(self):
217         import _auto_deps
218         _auto_deps.require_auto_deps()
219
220
221 class MakeExecutable(Command):
222     user_options = []
223     def initialize_options(self):
224         pass
225     def finalize_options(self):
226         pass
227     def run(self):
228         bin_tahoe_template = os.path.join("bin", "tahoe-script.template")
229
230         # Create the 'tahoe-script.py' file under the 'bin' directory. The
231         # 'tahoe-script.py' file is exactly the same as the
232         # 'tahoe-script.template' script except that the shebang line is
233         # rewritten to use our sys.executable for the interpreter. On
234         # Windows, create a tahoe.exe will execute it. On non-Windows, make a
235         # symlink to it from 'tahoe'. The tahoe.exe will be copied from the
236         # setuptools egg's cli.exe and this will work from a zip-safe and
237         # non-zip-safe setuptools egg.
238         f = open(bin_tahoe_template, "rU")
239         script_lines = f.readlines()
240         f.close()
241         script_lines[0] = "#!%s\n" % sys.executable
242         tahoe_script = os.path.join("bin", "tahoe-script.py")
243         f = open(tahoe_script, "w")
244         for line in script_lines:
245             f.write(line)
246         f.close()
247         if sys.platform == "win32":
248             from pkg_resources import require
249             setuptools_egg = require("setuptools")[0].location
250             if os.path.isfile(setuptools_egg):
251                 z = zipfile.ZipFile(setuptools_egg, 'r')
252                 for filename in z.namelist():
253                     if 'cli.exe' in filename:
254                         cli_exe = z.read(filename)
255             else:
256                 cli_exe = os.path.join(setuptools_egg, 'setuptools', 'cli.exe')
257             tahoe_exe = os.path.join("bin", "tahoe.exe")
258             if os.path.isfile(setuptools_egg):
259                 f = open(tahoe_exe, 'wb')
260                 f.write(cli_exe)
261                 f.close()
262             else:
263                 shutil.copy(cli_exe, tahoe_exe)
264         else:
265             try:
266                 os.remove(os.path.join('bin', 'tahoe'))
267             except:
268                 # okay, probably it was already gone
269                 pass
270             os.symlink('tahoe-script.py', os.path.join('bin', 'tahoe'))
271
272         # chmod +x bin/tahoe-script.py
273         old_mode = stat.S_IMODE(os.stat(tahoe_script)[stat.ST_MODE])
274         new_mode = old_mode | (stat.S_IXUSR | stat.S_IRUSR |
275                                stat.S_IXGRP | stat.S_IRGRP |
276                                stat.S_IXOTH | stat.S_IROTH )
277         os.chmod(tahoe_script, new_mode)
278
279 class MySdist(sdist.sdist):
280     """ A hook in the sdist command so that we can determine whether this the
281     tarball should be 'SUMO' or not, i.e. whether or not to include the
282     external dependency tarballs. Note that we always include
283     misc/dependencies/* in the tarball; --sumo controls whether tahoe-deps/*
284     is included as well.
285     """
286
287     user_options = sdist.sdist.user_options + \
288         [('sumo', 's',
289           "create a 'sumo' sdist which includes the contents of tahoe-deps/*"),
290          ]
291     boolean_options = ['sumo']
292
293     def initialize_options(self):
294         sdist.sdist.initialize_options(self)
295         self.sumo = False
296
297     def make_distribution(self):
298         # add our extra files to the list just before building the
299         # tarball/zipfile. We override make_distribution() instead of run()
300         # because setuptools.command.sdist.run() does not lend itself to
301         # easy/robust subclassing (the code we need to add goes right smack
302         # in the middle of a 12-line method). If this were the distutils
303         # version, we'd override get_file_list().
304
305         if self.sumo:
306             # If '--sumo' was specified, include tahoe-deps/* in the sdist.
307             # We assume that the user has fetched the tahoe-deps.tar.gz
308             # tarball and unpacked it already.
309             self.filelist.extend([os.path.join("tahoe-deps", fn)
310                                   for fn in os.listdir("tahoe-deps")])
311             # In addition, we want the tarball/zipfile to have -SUMO in the
312             # name, and the unpacked directory to have -SUMO too. The easiest
313             # way to do this is to patch self.distribution and override the
314             # get_fullname() method. (an alternative is to modify
315             # self.distribution.metadata.version, but that also affects the
316             # contents of PKG-INFO).
317             fullname = self.distribution.get_fullname()
318             def get_fullname():
319                 return fullname + "-SUMO"
320             self.distribution.get_fullname = get_fullname
321
322         return sdist.sdist.make_distribution(self)
323
324 # Tahoe's dependencies are managed by the find_links= entry in setup.cfg and
325 # the _auto_deps.install_requires list, which is used in the call to setup()
326 # below.
327 from _auto_deps import install_requires
328
329 APPNAME='allmydata-tahoe'
330 APPNAMEFILE = os.path.join('src', 'allmydata', '_appname.py')
331 APPNAMEFILESTR = "__appname__ = '%s'" % (APPNAME,)
332 try:
333     curappnamefilestr = open(APPNAMEFILE, 'rU').read()
334 except EnvironmentError:
335     # No file, or unreadable or something, okay then let's try to write one.
336     open(APPNAMEFILE, "w").write(APPNAMEFILESTR)
337 else:
338     if curappnamefilestr.strip() != APPNAMEFILESTR:
339         print "Error -- this setup.py file is configured with the 'application name' to be '%s', but there is already a file in place in '%s' which contains the contents '%s'.  If the file is wrong, please remove it and setup.py will regenerate it and write '%s' into it." % (APPNAME, APPNAMEFILE, curappnamefilestr, APPNAMEFILESTR)
340         sys.exit(-1)
341
342 setup_args = {}
343 if version:
344     setup_args["version"] = version
345
346 setup(name=APPNAME,
347       description='secure, decentralized, fault-tolerant filesystem',
348       long_description=open('README.txt', 'rU').read(),
349       author='the Tahoe-LAFS project',
350       author_email='tahoe-dev@allmydata.org',
351       url='http://tahoe-lafs.org/',
352       license='GNU GPL', # see README.txt -- there is an alternative licence
353       cmdclass={"show_supportlib": ShowSupportLib,
354                 "show_pythonpath": ShowPythonPath,
355                 "run_with_pythonpath": RunWithPythonPath,
356                 "check_auto_deps": CheckAutoDeps,
357                 "test_mac_diskimage": TestMacDiskImage,
358                 "make_executable": MakeExecutable,
359                 "sdist": MySdist,
360                 },
361       package_dir = {'':'src'},
362       packages=find_packages("src"),
363       classifiers=trove_classifiers,
364       test_suite="allmydata.test",
365       install_requires=install_requires,
366       include_package_data=True,
367       setup_requires=setup_requires,
368       entry_points = { 'console_scripts': [ 'tahoe = allmydata.scripts.runner:run' ] },
369       zip_safe=False, # We prefer unzipped for easier access.
370       **setup_args
371       )