2 # -*- coding: utf-8 -*-
4 # Tahoe-LAFS -- secure, distributed storage grid
6 # Copyright © 2008-2010 Allmydata, Inc.
8 # This file is part of Tahoe-LAFS.
10 # See the docs/about.html file for licensing information.
12 import glob, 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")
41 egg = os.path.realpath(glob.glob('setuptools-*.egg')[0])
42 sys.path.insert(0, egg)
43 import setuptools; setuptools.bootstrap_install_from = egg
45 from setuptools import find_packages, setup
46 from setuptools.command import sdist
47 from setuptools import Command
49 # Make the dependency-version-requirement, which is used by the Makefile at
50 # build-time, also available to the app at runtime:
51 shutil.copyfile("_auto_deps.py",
52 os.path.join("src", "allmydata", "_auto_deps.py"))
55 "Development Status :: 5 - Production/Stable",
56 "Environment :: Console",
57 "Environment :: Web Environment",
58 "License :: OSI Approved :: GNU General Public License (GPL)",
59 "License :: DFSG approved",
60 "License :: Other/Proprietary License",
61 "Intended Audience :: Developers",
62 "Intended Audience :: End Users/Desktop",
63 "Intended Audience :: System Administrators",
64 "Operating System :: Microsoft",
65 "Operating System :: Microsoft :: Windows",
66 "Operating System :: Microsoft :: Windows :: Windows NT/2000",
67 "Operating System :: Unix",
68 "Operating System :: POSIX :: Linux",
69 "Operating System :: POSIX",
70 "Operating System :: MacOS :: MacOS X",
71 "Operating System :: OS Independent",
72 "Natural Language :: English",
73 "Programming Language :: C",
74 "Programming Language :: Python",
75 "Programming Language :: Python :: 2",
76 "Programming Language :: Python :: 2.4",
77 "Programming Language :: Python :: 2.5",
78 "Programming Language :: Python :: 2.6",
80 "Topic :: System :: Systems Administration",
81 "Topic :: System :: Filesystems",
82 "Topic :: System :: Distributed Computing",
83 "Topic :: Software Development :: Libraries",
84 "Topic :: Communications :: Usenet News",
85 "Topic :: System :: Archiving :: Backup",
86 "Topic :: System :: Archiving :: Mirroring",
87 "Topic :: System :: Archiving",
93 # The darcsver command from the darcsver plugin is needed to initialize the
94 # distribution's .version attribute correctly. (It does this either by
95 # examining darcs history, or if that fails by reading the
96 # src/allmydata/_version.py file). darcsver will also write a new version
97 # stamp in src/allmydata/_version.py, with a version number derived from
98 # darcs history. Note that the setup.cfg file has an "[aliases]" section
99 # which enumerates commands that you might run and specifies that it will run
100 # darcsver before each one. If you add different commands (or if I forgot
101 # some that are already in use), you may need to add it to setup.cfg and
102 # configure it to run darcsver before your command, if you want the version
103 # number to be correct when that command runs.
104 # http://pypi.python.org/pypi/darcsver
105 setup_requires.append('darcsver >= 1.2.0')
107 # Nevow requires Twisted to setup, but doesn't declare that requirement in a
108 # way that enables setuptools to satisfy that requirement before Nevow's
109 # setup.py tried to "import twisted". Fortunately we require setuptools_trial
110 # to setup and setuptools_trial requires Twisted to install, so hopefully
111 # everything will work out until the Nevow issue is fixed:
112 # http://divmod.org/trac/ticket/2629 setuptools_trial is needed if you want
113 # "./setup.py trial" or "./setup.py test" to execute the tests (and in order
114 # to make sure Twisted is installed early enough -- see the paragraph above).
115 # http://pypi.python.org/pypi/setuptools_trial
116 setup_requires.extend(['setuptools_trial >= 0.5'])
118 # setuptools_darcs is required to produce complete distributions (such as
119 # with "sdist" or "bdist_egg") (unless there is a PKG-INFO file present which
120 # shows that this is itself a source distribution). For simplicity, and
121 # because there is some unknown error with setuptools_darcs when building and
122 # testing tahoe all in one python command on some platforms, we always add it
123 # to setup_requires. http://pypi.python.org/pypi/setuptools_darcs
124 setup_requires.append('setuptools_darcs >= 1.1.0')
126 # trialcoverage is required if you want the "trial" unit test runner to have a
127 # "--reporter=bwverbose-coverage" option which produces code-coverage results.
128 # The required version is 0.3.3, because that is the latest version that only
129 # depends on a version of pycoverage for which binary packages are available.
130 if "--reporter=bwverbose-coverage" in sys.argv:
131 setup_requires.append('trialcoverage >= 0.3.3')
133 # stdeb is required to produce Debian files with the "sdist_dsc" command.
134 if "sdist_dsc" in sys.argv:
135 setup_requires.append('stdeb >= 0.3')
138 # Mock - Mocking and Testing Library
139 # http://www.voidspace.org.uk/python/mock/
143 class ShowSupportLib(Command):
145 def initialize_options(self):
147 def finalize_options(self):
150 # TODO: --quiet suppresses the 'running show_supportlib' message.
151 # Find a way to do this all the time.
152 print supportlib # TODO windowsy
154 class ShowPythonPath(Command):
156 def initialize_options(self):
158 def finalize_options(self):
161 # TODO: --quiet suppresses the 'running show_supportlib' message.
162 # Find a way to do this all the time.
163 print "PYTHONPATH=%s" % os.environ.get("PYTHONPATH", '')
165 class RunWithPythonPath(Command):
166 description = "Run a subcommand with PYTHONPATH set appropriately"
168 user_options = [ ("python", "p",
169 "Treat command string as arguments to a python executable"),
170 ("command=", "c", "Command to be run"),
171 ("directory=", "d", "Directory to run the command in"),
173 boolean_options = ["python"]
175 def initialize_options(self):
178 self.directory = None
179 def finalize_options(self):
182 oldpp = os.environ.get("PYTHONPATH", "").split(os.pathsep)
184 # grr silly split() behavior
186 os.environ['PYTHONPATH'] = os.pathsep.join(oldpp + [supportlib,])
188 # We must require the command to be safe to split on
189 # whitespace, and have --python and --directory to make it
190 # easier to achieve this.
194 command.append(sys.executable)
196 command.extend(self.command.split())
198 raise RuntimeError("The --command argument is mandatory")
200 os.chdir(self.directory)
202 print "command =", " ".join(command)
203 rc = subprocess.call(command)
206 class TestMacDiskImage(Command):
208 def initialize_options(self):
210 def finalize_options(self):
214 sys.path.append(os.path.join('misc', 'build_helpers'))
215 import test_mac_diskimage
216 return test_mac_diskimage.test_mac_diskimage('Allmydata', version=self.distribution.metadata.version)
218 class CheckAutoDeps(Command):
220 def initialize_options(self):
222 def finalize_options(self):
226 _auto_deps.require_auto_deps()
229 class MakeExecutable(Command):
231 def initialize_options(self):
233 def finalize_options(self):
236 bin_tahoe_template = os.path.join("bin", "tahoe-script.template")
238 if sys.platform == 'win32':
239 # 'tahoe' script is needed for cygwin
240 script_names = ["tahoe.pyscript", "tahoe"]
242 script_names = ["tahoe"]
244 # Create the tahoe script file under the 'bin' directory. This
245 # file is exactly the same as the 'tahoe-script.template' script
246 # except that the shebang line is rewritten to use our sys.executable
247 # for the interpreter.
248 f = open(bin_tahoe_template, "rU")
249 script_lines = f.readlines()
251 script_lines[0] = '#!%s\n' % (sys.executable,)
252 for script_name in script_names:
253 tahoe_script = os.path.join("bin", script_name)
255 os.remove(tahoe_script)
257 if os.path.exists(tahoe_script):
259 f = open(tahoe_script, "wb")
260 for line in script_lines:
265 old_mode = stat.S_IMODE(os.stat(tahoe_script)[stat.ST_MODE])
266 new_mode = old_mode | (stat.S_IXUSR | stat.S_IRUSR |
267 stat.S_IXGRP | stat.S_IRGRP |
268 stat.S_IXOTH | stat.S_IROTH )
269 os.chmod(tahoe_script, new_mode)
271 old_tahoe_exe = os.path.join("bin", "tahoe.exe")
273 os.remove(old_tahoe_exe)
275 if os.path.exists(old_tahoe_exe):
279 class MySdist(sdist.sdist):
280 """ A hook in the sdist command so that we can determine whether this the
281 tarball should be 'SUMO' or not, i.e. whether or not to include the
282 external dependency tarballs. Note that we always include
283 misc/dependencies/* in the tarball; --sumo controls whether tahoe-deps/*
287 user_options = sdist.sdist.user_options + \
289 "create a 'sumo' sdist which includes the contents of tahoe-deps/*"),
291 boolean_options = ['sumo']
293 def initialize_options(self):
294 sdist.sdist.initialize_options(self)
297 def make_distribution(self):
298 # add our extra files to the list just before building the
299 # tarball/zipfile. We override make_distribution() instead of run()
300 # because setuptools.command.sdist.run() does not lend itself to
301 # easy/robust subclassing (the code we need to add goes right smack
302 # in the middle of a 12-line method). If this were the distutils
303 # version, we'd override get_file_list().
306 # If '--sumo' was specified, include tahoe-deps/* in the sdist.
307 # We assume that the user has fetched the tahoe-deps.tar.gz
308 # tarball and unpacked it already.
309 self.filelist.extend([os.path.join("tahoe-deps", fn)
310 for fn in os.listdir("tahoe-deps")])
311 # In addition, we want the tarball/zipfile to have -SUMO in the
312 # name, and the unpacked directory to have -SUMO too. The easiest
313 # way to do this is to patch self.distribution and override the
314 # get_fullname() method. (an alternative is to modify
315 # self.distribution.metadata.version, but that also affects the
316 # contents of PKG-INFO).
317 fullname = self.distribution.get_fullname()
319 return fullname + "-SUMO"
320 self.distribution.get_fullname = get_fullname
322 return sdist.sdist.make_distribution(self)
324 # Tahoe's dependencies are managed by the find_links= entry in setup.cfg and
325 # the _auto_deps.install_requires list, which is used in the call to setup()
327 from _auto_deps import install_requires
329 APPNAME='allmydata-tahoe'
330 APPNAMEFILE = os.path.join('src', 'allmydata', '_appname.py')
331 APPNAMEFILESTR = "__appname__ = '%s'" % (APPNAME,)
333 curappnamefilestr = open(APPNAMEFILE, 'rU').read()
334 except EnvironmentError:
335 # No file, or unreadable or something, okay then let's try to write one.
336 open(APPNAMEFILE, "w").write(APPNAMEFILESTR)
338 if curappnamefilestr.strip() != APPNAMEFILESTR:
339 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)
344 setup_args["version"] = version
347 description='secure, decentralized, fault-tolerant filesystem',
348 long_description=open('README.txt', 'rU').read(),
349 author='the Tahoe-LAFS project',
350 author_email='tahoe-dev@allmydata.org',
351 url='http://tahoe-lafs.org/',
352 license='GNU GPL', # see README.txt -- there is an alternative licence
353 cmdclass={"show_supportlib": ShowSupportLib,
354 "show_pythonpath": ShowPythonPath,
355 "run_with_pythonpath": RunWithPythonPath,
356 "check_auto_deps": CheckAutoDeps,
357 "test_mac_diskimage": TestMacDiskImage,
358 "make_executable": MakeExecutable,
361 package_dir = {'':'src'},
362 packages=find_packages("src"),
363 classifiers=trove_classifiers,
364 test_suite="allmydata.test",
365 install_requires=install_requires,
366 tests_require=tests_require,
367 include_package_data=True,
368 setup_requires=setup_requires,
369 entry_points = { 'console_scripts': [ 'tahoe = allmydata.scripts.runner:run' ] },
370 zip_safe=False, # We prefer unzipped for easier access.