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