3 # Allmydata Tahoe -- secure, distributed storage grid
5 # Copyright (C) 2008 Allmydata, Inc.
7 # This file is part of tahoe.
9 # See the docs/about.html file for licensing information.
11 import os, re, shutil, stat, subprocess, sys, zipfile
13 ##### sys.path management
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")
20 return os.path.join(prefixdir, "lib", pyver, "site-packages")
22 basedir = os.path.dirname(os.path.abspath(__file__))
23 supportlib = pylibdir(os.path.join(basedir, "support"))
25 for i in range(len(sys.argv)):
27 if arg == "build_tahoe":
29 sys.argv.extend(["develop", "--prefix=support", "--script-dir=support/bin"])
31 for i in range(len(sys.argv)):
34 if arg.startswith("--prefix="):
35 prefixdir = arg[len("--prefix="):]
37 if len(sys.argv) > i+1:
38 prefixdir = sys.argv[i+1]
41 libdir = pylibdir(prefixdir)
44 except EnvironmentError, le:
45 # Okay, maybe the dir was already there.
47 sys.path.append(libdir)
48 pp = os.environ.get('PYTHONPATH','').split(os.pathsep)
50 os.environ['PYTHONPATH'] = os.pathsep.join(pp)
52 if arg.startswith("build"):
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)
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])
71 from ez_setup import use_setuptools
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.
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
82 use_setuptools(download_delay=0, min_version="0.6c10dev")
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
90 pkg_resources.require('setuptools_trial')
91 from setuptools_trial.setuptools_trial import TrialTest
93 # Make the dependency-version-requirement, which is used by the Makefile at
94 # build-time, also available to the app at runtime:
96 shutil.copyfile("_auto_deps.py", os.path.join("src", "allmydata", "_auto_deps.py"))
99 "Development Status :: 5 - Production/Stable",
100 "Environment :: Console",
101 "Environment :: Web Environment",
102 "License :: OSI Approved :: GNU General Public License (GPL)",
103 "License :: DFSG approved",
104 "License :: Other/Proprietary License",
105 "Intended Audience :: Developers",
106 "Intended Audience :: End Users/Desktop",
107 "Intended Audience :: System Administrators",
108 "Operating System :: Microsoft",
109 "Operating System :: Microsoft :: Windows",
110 "Operating System :: Microsoft :: Windows :: Windows NT/2000",
111 "Operating System :: Unix",
112 "Operating System :: POSIX :: Linux",
113 "Operating System :: POSIX",
114 "Operating System :: MacOS :: MacOS X",
115 "Operating System :: OS Independent",
116 "Natural Language :: English",
117 "Programming Language :: C",
118 "Programming Language :: Python",
119 "Programming Language :: Python :: 2",
120 "Programming Language :: Python :: 2.4",
121 "Programming Language :: Python :: 2.5",
122 "Topic :: Utilities",
123 "Topic :: System :: Systems Administration",
124 "Topic :: System :: Filesystems",
125 "Topic :: System :: Distributed Computing",
126 "Topic :: Software Development :: Libraries",
127 "Topic :: Communications :: Usenet News",
128 "Topic :: System :: Archiving :: Backup",
129 "Topic :: System :: Archiving :: Mirroring",
130 "Topic :: System :: Archiving",
134 VERSIONFILE = "src/allmydata/_version.py"
137 verstrline = open(VERSIONFILE, "rt").read()
138 except EnvironmentError:
139 pass # Okay, there is no version file.
141 VSRE = r"^verstr = ['\"]([^'\"]*)['\"]"
142 mo = re.search(VSRE, verstrline, re.M)
146 print "unable to find version in %s" % (VERSIONFILE,)
147 raise RuntimeError("if %s.py exists, it is required to be well-formed" % (VERSIONFILE,))
150 """Welcome to the Tahoe project, a secure, decentralized, fault-tolerant
151 filesystem. All of the source code is available under a Free Software, Open
154 This filesystem is encrypted and spread over multiple peers in such a way that
155 it remains available even when some of the peers are unavailable,
156 malfunctioning, or malicious."""
161 # Nevow requires Twisted to setup, but doesn't declare that requirement in a way that enables
162 # setuptools to satisfy that requirement before Nevow's setup.py tried to "import twisted".
163 setup_requires.extend(['Twisted >= 2.4.0', 'setuptools_trial'])
165 # darcsver is needed only if you want "./setup.py darcsver" to write a new
166 # version stamp in src/allmydata/_version.py, with a version number derived from
168 # http://pypi.python.org/pypi/darcsver
169 if 'darcsver' in sys.argv[1:]:
170 setup_requires.append('darcsver >= 1.1.5')
172 # setuptools_trial is needed only if you want "./setup.py trial" to execute the tests.
173 # http://pypi.python.org/pypi/setuptools_trial
174 if 'trial' in sys.argv[1:]:
175 setup_requires.append('setuptools_trial >= 0.2')
177 # setuptools_darcs is required to produce complete distributions (such as with
178 # "sdist" or "bdist_egg"), unless there is a PKG-INFO file present which shows
179 # that this is itself a source distribution.
180 # http://pypi.python.org/pypi/setuptools_darcs
181 if not os.path.exists('PKG-INFO'):
182 setup_requires.append('setuptools_darcs >= 1.1.0')
184 class ShowSupportLib(Command):
186 def initialize_options(self):
188 def finalize_options(self):
191 # TODO: --quiet suppresses the 'running show_supportlib' message.
192 # Find a way to do this all the time.
193 print supportlib # TODO windowsy
195 class ShowPythonPath(Command):
197 def initialize_options(self):
199 def finalize_options(self):
202 # TODO: --quiet suppresses the 'running show_supportlib' message.
203 # Find a way to do this all the time.
204 print "PYTHONPATH=%s" % os.environ["PYTHONPATH"]
206 class RunWithPythonPath(Command):
207 description = "Run a subcommand with PYTHONPATH set appropriately"
209 user_options = [ ("python", "p",
210 "Treat command string as arguments to a python executable"),
211 ("command=", "c", "Command to be run"),
212 ("directory=", "d", "Directory to run the command in"),
214 boolean_options = ["python"]
216 def initialize_options(self):
219 self.directory = None
220 def finalize_options(self):
223 # os.environ['PYTHONPATH'] is already set by add_tahoe_paths, so we
224 # just need to exec() their command. We must require the command to
225 # be safe to split on whitespace, and have --python and --directory
226 # to make it easier to achieve this.
229 command.append(sys.executable)
231 command.extend(self.command.split())
233 raise RuntimeError("The --command argument is mandatory")
235 os.chdir(self.directory)
237 print "command =", " ".join(command)
238 rc = subprocess.call(command)
241 class CheckAutoDeps(Command):
243 def initialize_options(self):
245 def finalize_options(self):
249 _auto_deps.require_auto_deps()
252 class BuildTahoe(Command):
254 def initialize_options(self):
256 def finalize_options(self):
259 # On Windows, create the 'tahoe-script.py' file based on the 'tahoe'
260 # executable script under the 'bin' directory so that the tahoe.exe
261 # will work correctly. The 'tahoe-script.py' file is exactly the same
262 # as the 'tahoe' script except that we need to update the she-bang
263 # line. The tahoe.exe will be copied from the setuptools egg's cli.exe
264 # and this will work from a zip-safe and non-zip-safe setuptools egg.
265 if sys.platform == "win32":
266 setuptools_egg = require("setuptools")[0].location
267 if os.path.isfile(setuptools_egg):
268 z = zipfile.ZipFile(setuptools_egg, 'r')
269 for filename in z.namelist():
270 if 'cli.exe' in filename:
271 cli_exe = z.read(filename)
273 cli_exe = os.path.join(setuptools_egg, 'setuptools', 'cli.exe')
274 tahoe_exe = os.path.join("bin", "tahoe.exe")
275 if os.path.isfile(setuptools_egg):
276 f = open(tahoe_exe, 'wb')
280 shutil.copy(cli_exe, tahoe_exe)
281 bin_tahoe = os.path.join("bin", "tahoe")
282 f = open(bin_tahoe, "r")
283 script_lines = f.readlines()
285 script_lines[0] = "#!%s\n" % sys.executable
286 tahoe_script = os.path.join("bin", "tahoe-script.py")
287 f = open(tahoe_script, "w")
288 for line in script_lines:
292 command = [sys.executable, "setup.py", "develop", "--prefix", "support"]
293 print "Command:", " ".join(command)
294 rc = subprocess.call(command)
296 print >>sys.stderr, "'setup.py develop' terminated by signal", -rc
299 print >>sys.stderr, "'setup.py develop' exited with rc", rc
302 class Trial(TrialTest):
303 # Custom sub-class of the TrialTest class from the setuptools_trial
304 # plugin so that we can ensure certain options are set by default.
307 # setup.py trial # run all tests
308 # setup.py trial -a allmydata.test.test_util # run some tests
309 # setup.py trial -a '--reporter=text allmydata.test.test_util' #other args
312 def initialize_options(self):
313 TrialTest.initialize_options(self)
315 # We want to set the reactor to 'poll', because of bug #402
316 # (twisted bug #3218).
317 if sys.platform in ("linux2", "cygwin"):
318 # poll on linux2 to avoid #402 problems with select
319 # poll on cygwin since selectreactor runs out of fds
320 self.reactor = "poll"
323 class MySdist(sdist.sdist):
324 """ A hook in the sdist command so that we can determine whether this the
325 tarball should be 'SUMO' or not, i.e. whether or not to include the
326 external dependency tarballs. Note that we always include
327 misc/dependencies/* in the tarball; --sumo controls whether tahoe-deps/*
331 user_options = sdist.sdist.user_options + \
333 "create a 'sumo' sdist which includes the contents of tahoe-deps/*"),
335 boolean_options = ['sumo']
337 def initialize_options(self):
338 sdist.sdist.initialize_options(self)
341 def make_distribution(self):
342 # add our extra files to the list just before building the
343 # tarball/zipfile. We override make_distribution() instead of run()
344 # because setuptools.command.sdist.run() does not lend itself to
345 # easy/robust subclassing (the code we need to add goes right smack
346 # in the middle of a 12-line method). If this were the distutils
347 # version, we'd override get_file_list().
350 # If '--sumo' was specified, include tahoe-deps/* in the sdist.
351 # We assume that the user has fetched the tahoe-deps.tar.gz
352 # tarball and unpacked it already.
353 self.filelist.extend([os.path.join("tahoe-deps", fn)
354 for fn in os.listdir("tahoe-deps")])
355 # In addition, we want the tarball/zipfile to have -SUMO in the
356 # name, and the unpacked directory to have -SUMO too. The easiest
357 # way to do this is to patch self.distribution and override the
358 # get_fullname() method. (an alternative is to modify
359 # self.distribution.metadata.version, but that also affects the
360 # contents of PKG-INFO).
361 fullname = self.distribution.get_fullname()
363 return fullname + "-SUMO"
364 self.distribution.get_fullname = get_fullname
366 return sdist.sdist.make_distribution(self)
368 # Tahoe's dependencies are managed by the find_links= entry in setup.cfg and
369 # the _auto_deps.install_requires list, which is used in the call to setup()
370 # at the end of this file
371 from _auto_deps import install_requires
373 setup(name='allmydata-tahoe',
375 description='secure, decentralized, fault-tolerant filesystem',
376 long_description=LONG_DESCRIPTION,
377 author='the allmydata.org Tahoe project',
378 author_email='tahoe-dev@allmydata.org',
379 url='http://allmydata.org/',
381 cmdclass={"show_supportlib": ShowSupportLib,
382 "show_pythonpath": ShowPythonPath,
383 "run_with_pythonpath": RunWithPythonPath,
384 "check_auto_deps": CheckAutoDeps,
385 "build_tahoe": BuildTahoe,
389 package_dir = {'':'src'},
390 packages=find_packages("src"),
391 classifiers=trove_classifiers,
392 test_suite="allmydata.test",
393 install_requires=install_requires,
394 include_package_data=True,
395 setup_requires=setup_requires,
396 entry_points = { 'console_scripts': [ 'tahoe = allmydata.scripts.runner:run' ] },
397 zip_safe=False, # We prefer unzipped for easier access.