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