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 prefixdirs = [] # argh! horrible kludge to work-around setuptools #54
26 for i in range(len(sys.argv)):
28 if arg.startswith("--prefix="):
29 prefixdirs.append(arg[len("--prefix="):])
31 if len(sys.argv) > i+1:
32 prefixdirs.append(sys.argv[i+1])
34 # The following horrible kludge to workaround setuptools #17 is commented-out, because I can't at this moment figure out how to make sure the horrible kludge gets executed only when it is needed (i.e., only when a "setup.py develop" step is about to happen), and the bad effect of setuptools #17 is "only" that setuptools re-installs extant packages.
35 # if arg.startswith("develop") or arg.startswith("build") or arg.startswith("test"): # argh! horrible kludge to workaround setuptools #17
36 # if sys.platform == "linux2":
37 # # workaround for tahoe #229 / setuptools #17, on debian
38 # sys.argv.extend(["--site-dirs", "/var/lib/python-support/python%d.%d" % (sys.version_info[:2])])
39 # elif sys.platform == "darwin":
40 # # this probably only applies to leopard 10.5, possibly only 10.5.5
41 # sd = "/System/Library/Frameworks/Python.framework/Versions/%d.%d/Extras/lib/python" % (sys.version_info[:2])
42 # sys.argv.extend(["--site-dirs", sd])
45 prefixdirs.append("support")
47 for prefixdir in prefixdirs:
48 libdir = pylibdir(prefixdir)
51 except EnvironmentError, le:
52 # Okay, maybe the dir was already there.
54 sys.path.append(libdir)
55 pp = os.environ.get('PYTHONPATH','').split(os.pathsep)
57 os.environ['PYTHONPATH'] = os.pathsep.join(pp)
60 from ez_setup import use_setuptools
64 # This invokes our own customized version of ez_setup.py to make sure that
65 # setuptools >= v0.6c8 (a.k.a. v0.6-final) is installed.
67 # setuptools < v0.6c8 doesn't handle eggs which get installed into the CWD
68 # as a result of being transitively depended on in a setup_requires, but
69 # then are needed for the installed code to run, i.e. in an
71 use_setuptools(download_delay=0, min_version="0.6c10dev")
73 from setuptools import find_packages, setup
74 from setuptools.command import sdist
75 from setuptools import Command
76 from pkg_resources import require
78 # Make the dependency-version-requirement, which is used by the Makefile at
79 # build-time, also available to the app at runtime:
81 shutil.copyfile("_auto_deps.py", os.path.join("src", "allmydata", "_auto_deps.py"))
84 "Development Status :: 5 - Production/Stable",
85 "Environment :: Console",
86 "Environment :: Web Environment",
87 "License :: OSI Approved :: GNU General Public License (GPL)",
88 "License :: DFSG approved",
89 "License :: Other/Proprietary License",
90 "Intended Audience :: Developers",
91 "Intended Audience :: End Users/Desktop",
92 "Intended Audience :: System Administrators",
93 "Operating System :: Microsoft",
94 "Operating System :: Microsoft :: Windows",
95 "Operating System :: Microsoft :: Windows :: Windows NT/2000",
96 "Operating System :: Unix",
97 "Operating System :: POSIX :: Linux",
98 "Operating System :: POSIX",
99 "Operating System :: MacOS :: MacOS X",
100 "Operating System :: OS Independent",
101 "Natural Language :: English",
102 "Programming Language :: C",
103 "Programming Language :: Python",
104 "Programming Language :: Python :: 2",
105 "Programming Language :: Python :: 2.4",
106 "Programming Language :: Python :: 2.5",
107 "Programming Language :: Python :: 2.6",
108 "Topic :: Utilities",
109 "Topic :: System :: Systems Administration",
110 "Topic :: System :: Filesystems",
111 "Topic :: System :: Distributed Computing",
112 "Topic :: Software Development :: Libraries",
113 "Topic :: Communications :: Usenet News",
114 "Topic :: System :: Archiving :: Backup",
115 "Topic :: System :: Archiving :: Mirroring",
116 "Topic :: System :: Archiving",
120 # Note that the darcsver command from the darcsver plugin is needed to initialize the
121 # distribution's .version attribute correctly. (It does this either by examining darcs history,
122 # or if that fails by reading the src/allmydata/_version.py file).
125 """Welcome to the Tahoe project, a secure, decentralized, fault-tolerant
126 filesystem. All of the source code is available under a Free Software, Open
129 This filesystem is encrypted and spread over multiple peers in such a way that
130 it remains available even when some of the peers are unavailable,
131 malfunctioning, or malicious."""
136 # Nevow requires Twisted to setup, but doesn't declare that requirement in a way that enables
137 # setuptools to satisfy that requirement before Nevow's setup.py tried to "import twisted".
138 # Fortunately we require setuptools_trial to setup and setuptools_trial requires Twisted to
139 # install, so hopefully everything will work out until the Nevow issue is fixed:
140 # http://divmod.org/trac/ticket/2629
141 # setuptools_trial is needed if you want "./setup.py trial" or "./setup.py test" to execute the
142 # tests (and in order to make sure Twisted is installed early enough -- see the paragraph
144 # http://pypi.python.org/pypi/setuptools_trial
145 setup_requires.extend(['setuptools_trial >= 0.5'])
147 # darcsver is needed if you want "./setup.py darcsver" to write a new version stamp in
148 # src/allmydata/_version.py, with a version number derived from darcs history.
149 # http://pypi.python.org/pypi/darcsver
150 setup_requires.append('darcsver >= 1.2.0')
152 # setuptools_darcs is required to produce complete distributions (such as with
153 # "sdist" or "bdist_egg"), unless there is a PKG-INFO file present which shows
154 # that this is itself a source distribution.
155 # http://pypi.python.org/pypi/setuptools_darcs
156 if not os.path.exists('PKG-INFO'):
157 setup_requires.append('setuptools_darcs >= 1.1.0')
159 class ShowSupportLib(Command):
161 def initialize_options(self):
163 def finalize_options(self):
166 # TODO: --quiet suppresses the 'running show_supportlib' message.
167 # Find a way to do this all the time.
168 print supportlib # TODO windowsy
170 class ShowPythonPath(Command):
172 def initialize_options(self):
174 def finalize_options(self):
177 # TODO: --quiet suppresses the 'running show_supportlib' message.
178 # Find a way to do this all the time.
179 print "PYTHONPATH=%s" % os.environ.get("PYTHONPATH", '')
181 class RunWithPythonPath(Command):
182 description = "Run a subcommand with PYTHONPATH set appropriately"
184 user_options = [ ("python", "p",
185 "Treat command string as arguments to a python executable"),
186 ("command=", "c", "Command to be run"),
187 ("directory=", "d", "Directory to run the command in"),
189 boolean_options = ["python"]
191 def initialize_options(self):
194 self.directory = None
195 def finalize_options(self):
198 oldpp = os.environ.get("PYTHONPATH", "").split(os.pathsep)
200 # grr silly split() behavior
202 os.environ['PYTHONPATH'] = os.pathsep.join(oldpp + [supportlib,])
204 # We must require the command to be safe to split on
205 # whitespace, and have --python and --directory to make it
206 # easier to achieve this.
210 command.append(sys.executable)
212 command.extend(self.command.split())
214 raise RuntimeError("The --command argument is mandatory")
216 os.chdir(self.directory)
218 print "command =", " ".join(command)
219 rc = subprocess.call(command)
222 class CheckAutoDeps(Command):
224 def initialize_options(self):
226 def finalize_options(self):
230 _auto_deps.require_auto_deps()
233 class MakeExecutable(Command):
235 def initialize_options(self):
237 def finalize_options(self):
240 bin_tahoe_template = os.path.join("bin", "tahoe-script.template")
242 # Create the 'tahoe-script.py' file under the 'bin' directory. The 'tahoe-script.py'
243 # file is exactly the same as the 'tahoe-script.template' script except that the shebang
244 # line is rewritten to use our sys.executable for the interpreter. On Windows, create a
245 # tahoe.exe will execute it. On non-Windows, make a symlink to it from 'tahoe'. The
246 # tahoe.exe will be copied from the setuptools egg's cli.exe and this will work from a
247 # zip-safe and non-zip-safe setuptools egg.
248 f = open(bin_tahoe_template, "rU")
249 script_lines = f.readlines()
251 script_lines[0] = "#!%s\n" % sys.executable
252 tahoe_script = os.path.join("bin", "tahoe-script.py")
253 f = open(tahoe_script, "w")
254 for line in script_lines:
257 if sys.platform == "win32":
258 setuptools_egg = require("setuptools")[0].location
259 if os.path.isfile(setuptools_egg):
260 z = zipfile.ZipFile(setuptools_egg, 'r')
261 for filename in z.namelist():
262 if 'cli.exe' in filename:
263 cli_exe = z.read(filename)
265 cli_exe = os.path.join(setuptools_egg, 'setuptools', 'cli.exe')
266 tahoe_exe = os.path.join("bin", "tahoe.exe")
267 if os.path.isfile(setuptools_egg):
268 f = open(tahoe_exe, 'wb')
272 shutil.copy(cli_exe, tahoe_exe)
275 os.remove(os.path.join('bin', 'tahoe'))
277 # okay, probably it was already gone
279 os.symlink('tahoe-script.py', os.path.join('bin', 'tahoe'))
281 # chmod +x bin/tahoe-script.py
282 old_mode = stat.S_IMODE(os.stat(tahoe_script)[stat.ST_MODE])
283 new_mode = old_mode | (stat.S_IXUSR | stat.S_IRUSR |
284 stat.S_IXGRP | stat.S_IRGRP |
285 stat.S_IXOTH | stat.S_IROTH )
286 os.chmod(tahoe_script, new_mode)
288 class MySdist(sdist.sdist):
289 """ A hook in the sdist command so that we can determine whether this the
290 tarball should be 'SUMO' or not, i.e. whether or not to include the
291 external dependency tarballs. Note that we always include
292 misc/dependencies/* in the tarball; --sumo controls whether tahoe-deps/*
296 user_options = sdist.sdist.user_options + \
298 "create a 'sumo' sdist which includes the contents of tahoe-deps/*"),
300 boolean_options = ['sumo']
302 def initialize_options(self):
303 sdist.sdist.initialize_options(self)
306 def make_distribution(self):
307 # add our extra files to the list just before building the
308 # tarball/zipfile. We override make_distribution() instead of run()
309 # because setuptools.command.sdist.run() does not lend itself to
310 # easy/robust subclassing (the code we need to add goes right smack
311 # in the middle of a 12-line method). If this were the distutils
312 # version, we'd override get_file_list().
315 # If '--sumo' was specified, include tahoe-deps/* in the sdist.
316 # We assume that the user has fetched the tahoe-deps.tar.gz
317 # tarball and unpacked it already.
318 self.filelist.extend([os.path.join("tahoe-deps", fn)
319 for fn in os.listdir("tahoe-deps")])
320 # In addition, we want the tarball/zipfile to have -SUMO in the
321 # name, and the unpacked directory to have -SUMO too. The easiest
322 # way to do this is to patch self.distribution and override the
323 # get_fullname() method. (an alternative is to modify
324 # self.distribution.metadata.version, but that also affects the
325 # contents of PKG-INFO).
326 fullname = self.distribution.get_fullname()
328 return fullname + "-SUMO"
329 self.distribution.get_fullname = get_fullname
331 return sdist.sdist.make_distribution(self)
333 # Tahoe's dependencies are managed by the find_links= entry in setup.cfg and
334 # the _auto_deps.install_requires list, which is used in the call to setup()
335 # at the end of this file
336 from _auto_deps import install_requires
338 setup(name='allmydata-tahoe',
339 description='secure, decentralized, fault-tolerant filesystem',
340 long_description=LONG_DESCRIPTION,
341 author='the allmydata.org Tahoe project',
342 author_email='tahoe-dev@allmydata.org',
343 url='http://allmydata.org/',
345 cmdclass={"show_supportlib": ShowSupportLib,
346 "show_pythonpath": ShowPythonPath,
347 "run_with_pythonpath": RunWithPythonPath,
348 "check_auto_deps": CheckAutoDeps,
349 "make_executable": MakeExecutable,
352 package_dir = {'':'src'},
353 packages=find_packages("src"),
354 classifiers=trove_classifiers,
355 test_suite="allmydata.test",
356 install_requires=install_requires,
357 include_package_data=True,
358 setup_requires=setup_requires,
359 entry_points = { 'console_scripts': [ 'tahoe = allmydata.scripts.runner:run' ] },
360 zip_safe=False, # We prefer unzipped for easier access.