3 # Allmydata Tahoe -- secure, distributed storage grid
5 # Copyright © 2008-2009 Allmydata, Inc.
7 # This file is part of Tahoe-LAFS.
9 # See the docs/about.html file for licensing information.
11 import os, shutil, stat, subprocess, sys, zipfile, re
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 # locate our version number
27 def read_version_py(infname):
29 verstrline = open(infname, "rt").read()
30 except EnvironmentError:
33 VSRE = r"^verstr = ['\"]([^'\"]*)['\"]"
34 mo = re.search(VSRE, verstrline, re.M)
38 version = read_version_py("src/allmydata/_version.py")
41 from ez_setup import use_setuptools
45 # This invokes our own customized version of ez_setup.py to make sure
46 # that setuptools v0.6c12dev (which is our own toothpick of setuptools)
47 # is used to build. Note that we can use any version of setuptools >=
48 # 0.6c6 to *run* -- see _auto_deps.py for run-time dependencies (a.k.a.
49 # "install_requires") -- this is only for build-time dependencies (a.k.a.
51 use_setuptools(download_delay=0, min_version="0.6c12dev")
53 from setuptools import find_packages, setup
54 from setuptools.command import sdist
55 from setuptools import Command
56 from pkg_resources import require
58 # Make the dependency-version-requirement, which is used by the Makefile at
59 # build-time, also available to the app at runtime:
60 shutil.copyfile("_auto_deps.py",
61 os.path.join("src", "allmydata", "_auto_deps.py"))
64 "Development Status :: 5 - Production/Stable",
65 "Environment :: Console",
66 "Environment :: Web Environment",
67 "License :: OSI Approved :: GNU General Public License (GPL)",
68 "License :: DFSG approved",
69 "License :: Other/Proprietary License",
70 "Intended Audience :: Developers",
71 "Intended Audience :: End Users/Desktop",
72 "Intended Audience :: System Administrators",
73 "Operating System :: Microsoft",
74 "Operating System :: Microsoft :: Windows",
75 "Operating System :: Microsoft :: Windows :: Windows NT/2000",
76 "Operating System :: Unix",
77 "Operating System :: POSIX :: Linux",
78 "Operating System :: POSIX",
79 "Operating System :: MacOS :: MacOS X",
80 "Operating System :: OS Independent",
81 "Natural Language :: English",
82 "Programming Language :: C",
83 "Programming Language :: Python",
84 "Programming Language :: Python :: 2",
85 "Programming Language :: Python :: 2.4",
86 "Programming Language :: Python :: 2.5",
87 "Programming Language :: Python :: 2.6",
89 "Topic :: System :: Systems Administration",
90 "Topic :: System :: Filesystems",
91 "Topic :: System :: Distributed Computing",
92 "Topic :: Software Development :: Libraries",
93 "Topic :: Communications :: Usenet News",
94 "Topic :: System :: Archiving :: Backup",
95 "Topic :: System :: Archiving :: Mirroring",
96 "Topic :: System :: Archiving",
101 """Welcome to the Tahoe project, a secure, decentralized, fault-tolerant
102 filesystem. All of the source code is available under a Free Software, Open
105 This filesystem is encrypted and spread over multiple peers in such a way that
106 it remains available even when some of the peers are unavailable,
107 malfunctioning, or malicious."""
112 # The darcsver command from the darcsver plugin is needed to initialize the
113 # distribution's .version attribute correctly. (It does this either by
114 # examining darcs history, or if that fails by reading the
115 # src/allmydata/_version.py file). darcsver will also write a new version
116 # stamp in src/allmydata/_version.py, with a version number derived from
117 # darcs history. Note that the setup.cfg file has an "[aliases]" section
118 # which enumerates commands that you might run and specifies that it will run
119 # darcsver before each one. If you add different commands (or if I forgot
120 # some that are already in use), you may need to add it to setup.cfg and
121 # configure it to run darcsver before your command, if you want the version
122 # number to be correct when that command runs.
123 # http://pypi.python.org/pypi/darcsver
124 setup_requires.append('darcsver >= 1.2.0')
126 # Nevow requires Twisted to setup, but doesn't declare that requirement in a
127 # way that enables setuptools to satisfy that requirement before Nevow's
128 # setup.py tried to "import twisted". Fortunately we require setuptools_trial
129 # to setup and setuptools_trial requires Twisted to install, so hopefully
130 # everything will work out until the Nevow issue is fixed:
131 # http://divmod.org/trac/ticket/2629 setuptools_trial is needed if you want
132 # "./setup.py trial" or "./setup.py test" to execute the tests (and in order
133 # to make sure Twisted is installed early enough -- see the paragraph above).
134 # http://pypi.python.org/pypi/setuptools_trial
135 setup_requires.extend(['setuptools_trial >= 0.5'])
137 # setuptools_darcs is required to produce complete distributions (such as
138 # with "sdist" or "bdist_egg") (unless there is a PKG-INFO file present which
139 # shows that this is itself a source distribution). For simplicity, and
140 # because there is some unknown error with setuptools_darcs when building and
141 # testing tahoe all in one python command on some platforms, we always add it
142 # to setup_requires. http://pypi.python.org/pypi/setuptools_darcs
143 setup_requires.append('setuptools_darcs >= 1.1.0')
145 # stdeb is required to produce Debian files with the "sdist_dsc" command.
146 if "sdist_dsc" in sys.argv:
147 setup_requires.append('stdeb >= 0.3')
149 class ShowSupportLib(Command):
151 def initialize_options(self):
153 def finalize_options(self):
156 # TODO: --quiet suppresses the 'running show_supportlib' message.
157 # Find a way to do this all the time.
158 print supportlib # TODO windowsy
160 class ShowPythonPath(Command):
162 def initialize_options(self):
164 def finalize_options(self):
167 # TODO: --quiet suppresses the 'running show_supportlib' message.
168 # Find a way to do this all the time.
169 print "PYTHONPATH=%s" % os.environ.get("PYTHONPATH", '')
171 class RunWithPythonPath(Command):
172 description = "Run a subcommand with PYTHONPATH set appropriately"
174 user_options = [ ("python", "p",
175 "Treat command string as arguments to a python executable"),
176 ("command=", "c", "Command to be run"),
177 ("directory=", "d", "Directory to run the command in"),
179 boolean_options = ["python"]
181 def initialize_options(self):
184 self.directory = None
185 def finalize_options(self):
188 oldpp = os.environ.get("PYTHONPATH", "").split(os.pathsep)
190 # grr silly split() behavior
192 os.environ['PYTHONPATH'] = os.pathsep.join(oldpp + [supportlib,])
194 # We must require the command to be safe to split on
195 # whitespace, and have --python and --directory to make it
196 # easier to achieve this.
200 command.append(sys.executable)
202 command.extend(self.command.split())
204 raise RuntimeError("The --command argument is mandatory")
206 os.chdir(self.directory)
208 print "command =", " ".join(command)
209 rc = subprocess.call(command)
212 class TestMacDiskImage(Command):
214 def initialize_options(self):
216 def finalize_options(self):
220 sys.path.append('misc')
221 import test_mac_diskimage
222 return test_mac_diskimage.test_mac_diskimage('Allmydata', version=self.distribution.metadata.version)
224 class CheckAutoDeps(Command):
226 def initialize_options(self):
228 def finalize_options(self):
232 _auto_deps.require_auto_deps()
235 class MakeExecutable(Command):
237 def initialize_options(self):
239 def finalize_options(self):
242 bin_tahoe_template = os.path.join("bin", "tahoe-script.template")
244 # Create the 'tahoe-script.py' file under the 'bin' directory. The
245 # 'tahoe-script.py' file is exactly the same as the
246 # 'tahoe-script.template' script except that the shebang line is
247 # rewritten to use our sys.executable for the interpreter. On
248 # Windows, create a tahoe.exe will execute it. On non-Windows, make a
249 # symlink to it from 'tahoe'. The tahoe.exe will be copied from the
250 # setuptools egg's cli.exe and this will work from a zip-safe and
251 # non-zip-safe setuptools egg.
252 f = open(bin_tahoe_template, "rU")
253 script_lines = f.readlines()
255 script_lines[0] = "#!%s\n" % sys.executable
256 tahoe_script = os.path.join("bin", "tahoe-script.py")
257 f = open(tahoe_script, "w")
258 for line in script_lines:
261 if sys.platform == "win32":
262 setuptools_egg = require("setuptools")[0].location
263 if os.path.isfile(setuptools_egg):
264 z = zipfile.ZipFile(setuptools_egg, 'r')
265 for filename in z.namelist():
266 if 'cli.exe' in filename:
267 cli_exe = z.read(filename)
269 cli_exe = os.path.join(setuptools_egg, 'setuptools', 'cli.exe')
270 tahoe_exe = os.path.join("bin", "tahoe.exe")
271 if os.path.isfile(setuptools_egg):
272 f = open(tahoe_exe, 'wb')
276 shutil.copy(cli_exe, tahoe_exe)
279 os.remove(os.path.join('bin', 'tahoe'))
281 # okay, probably it was already gone
283 os.symlink('tahoe-script.py', os.path.join('bin', 'tahoe'))
285 # chmod +x bin/tahoe-script.py
286 old_mode = stat.S_IMODE(os.stat(tahoe_script)[stat.ST_MODE])
287 new_mode = old_mode | (stat.S_IXUSR | stat.S_IRUSR |
288 stat.S_IXGRP | stat.S_IRGRP |
289 stat.S_IXOTH | stat.S_IROTH )
290 os.chmod(tahoe_script, new_mode)
292 class MySdist(sdist.sdist):
293 """ A hook in the sdist command so that we can determine whether this the
294 tarball should be 'SUMO' or not, i.e. whether or not to include the
295 external dependency tarballs. Note that we always include
296 misc/dependencies/* in the tarball; --sumo controls whether tahoe-deps/*
300 user_options = sdist.sdist.user_options + \
302 "create a 'sumo' sdist which includes the contents of tahoe-deps/*"),
304 boolean_options = ['sumo']
306 def initialize_options(self):
307 sdist.sdist.initialize_options(self)
310 def make_distribution(self):
311 # add our extra files to the list just before building the
312 # tarball/zipfile. We override make_distribution() instead of run()
313 # because setuptools.command.sdist.run() does not lend itself to
314 # easy/robust subclassing (the code we need to add goes right smack
315 # in the middle of a 12-line method). If this were the distutils
316 # version, we'd override get_file_list().
319 # If '--sumo' was specified, include tahoe-deps/* in the sdist.
320 # We assume that the user has fetched the tahoe-deps.tar.gz
321 # tarball and unpacked it already.
322 self.filelist.extend([os.path.join("tahoe-deps", fn)
323 for fn in os.listdir("tahoe-deps")])
324 # In addition, we want the tarball/zipfile to have -SUMO in the
325 # name, and the unpacked directory to have -SUMO too. The easiest
326 # way to do this is to patch self.distribution and override the
327 # get_fullname() method. (an alternative is to modify
328 # self.distribution.metadata.version, but that also affects the
329 # contents of PKG-INFO).
330 fullname = self.distribution.get_fullname()
332 return fullname + "-SUMO"
333 self.distribution.get_fullname = get_fullname
335 return sdist.sdist.make_distribution(self)
337 # Tahoe's dependencies are managed by the find_links= entry in setup.cfg and
338 # the _auto_deps.install_requires list, which is used in the call to setup()
340 from _auto_deps import install_requires
342 APPNAME='allmydata-tahoe'
343 APPNAMEFILE = os.path.join('src', 'allmydata', '_appname.py')
344 APPNAMEFILESTR = "__appname__ = '%s'" % (APPNAME,)
346 curappnamefilestr = open(APPNAMEFILE, 'rU').read()
347 except EnvironmentError:
348 # No file, or unreadable or something, okay then let's try to write one.
349 open(APPNAMEFILE, "w").write(APPNAMEFILESTR)
351 if curappnamefilestr.strip() != APPNAMEFILESTR:
352 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)
357 setup_args["version"] = version
360 description='secure, decentralized, fault-tolerant filesystem',
361 long_description=LONG_DESCRIPTION,
362 author='the allmydata.org Tahoe project',
363 author_email='tahoe-dev@allmydata.org',
364 url='http://allmydata.org/',
366 cmdclass={"show_supportlib": ShowSupportLib,
367 "show_pythonpath": ShowPythonPath,
368 "run_with_pythonpath": RunWithPythonPath,
369 "check_auto_deps": CheckAutoDeps,
370 "test_mac_diskimage": TestMacDiskImage,
371 "make_executable": MakeExecutable,
374 package_dir = {'':'src'},
375 packages=find_packages("src"),
376 classifiers=trove_classifiers,
377 test_suite="allmydata.test",
378 install_requires=install_requires,
379 include_package_data=True,
380 setup_requires=setup_requires,
381 entry_points = { 'console_scripts': [ 'tahoe = allmydata.scripts.runner:run' ] },
382 zip_safe=False, # We prefer unzipped for easier access.