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 APPNAME='allmydata-tahoe'
42 APPNAMEFILE = os.path.join('src', 'allmydata', '_appname.py')
43 APPNAMEFILESTR = "__appname__ = '%s'" % (APPNAME,)
45 curappnamefilestr = open(APPNAMEFILE, 'rU').read()
46 except EnvironmentError:
47 # No file, or unreadable or something, okay then let's try to write one.
48 open(APPNAMEFILE, "w").write(APPNAMEFILESTR)
50 if curappnamefilestr.strip() != APPNAMEFILESTR:
51 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)
54 # setuptools/zetuptoolz looks in __main__.__requires__ for a list of
55 # requirements. When running "python setup.py test", __main__ is
56 # setup.py, so we put the list here so that the requirements will be
57 # available for tests:
59 # Tahoe's dependencies are managed by the find_links= entry in setup.cfg and
60 # the _auto_deps.install_requires list, which is used in the call to setup()
63 execfile('src/allmydata/_auto_deps.py', adglobals)
64 install_requires = adglobals['install_requires']
66 __requires__ = install_requires[:]
67 if 'trial' in sys.argv or 'test' in sys.argv:
68 if version is not None:
69 __requires__.append(APPNAME + '==' + version)
71 __requires__.append(APPNAME)
73 egg = os.path.realpath(glob.glob('setuptools-*.egg')[0])
74 sys.path.insert(0, egg)
75 egg = os.path.realpath(glob.glob('darcsver-*.egg')[0])
76 sys.path.insert(0, egg)
77 import setuptools; setuptools.bootstrap_install_from = egg
79 from setuptools import find_packages, setup
80 from setuptools.command import sdist
81 from setuptools import Command
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 "Programming Language :: Python :: 2.7",
109 "Topic :: Utilities",
110 "Topic :: System :: Systems Administration",
111 "Topic :: System :: Filesystems",
112 "Topic :: System :: Distributed Computing",
113 "Topic :: Software Development :: Libraries",
114 "Topic :: Communications :: Usenet News",
115 "Topic :: System :: Archiving :: Backup",
116 "Topic :: System :: Archiving :: Mirroring",
117 "Topic :: System :: Archiving",
123 # The darcsver command from the darcsver plugin is needed to initialize the
124 # distribution's .version attribute correctly. (It does this either by
125 # examining darcs history, or if that fails by reading the
126 # src/allmydata/_version.py file). darcsver will also write a new version
127 # stamp in src/allmydata/_version.py, with a version number derived from
128 # darcs history. Note that the setup.cfg file has an "[aliases]" section
129 # which enumerates commands that you might run and specifies that it will run
130 # darcsver before each one. If you add different commands (or if I forgot
131 # some that are already in use), you may need to add it to setup.cfg and
132 # configure it to run darcsver before your command, if you want the version
133 # number to be correct when that command runs.
134 # http://pypi.python.org/pypi/darcsver
135 setup_requires.append('darcsver >= 1.7.1')
137 # Nevow requires Twisted to setup, but doesn't declare that requirement in a
138 # way that enables setuptools to satisfy that requirement before Nevow's
139 # setup.py tried to "import twisted". Fortunately we require setuptools_trial
140 # to setup and setuptools_trial requires Twisted to install, so hopefully
141 # everything will work out until the Nevow issue is fixed:
142 # http://divmod.org/trac/ticket/2629 setuptools_trial is needed if you want
143 # "./setup.py trial" or "./setup.py test" to execute the tests (and in order
144 # to make sure Twisted is installed early enough -- see the paragraph above).
145 # http://pypi.python.org/pypi/setuptools_trial
146 setup_requires.extend(['setuptools_trial >= 0.5'])
148 # setuptools_darcs is required to produce complete distributions (such as
149 # with "sdist" or "bdist_egg") (unless there is a PKG-INFO file present which
150 # shows that this is itself a source distribution). For simplicity, and
151 # because there is some unknown error with setuptools_darcs when building and
152 # testing tahoe all in one python command on some platforms, we always add it
153 # to setup_requires. http://pypi.python.org/pypi/setuptools_darcs
154 setup_requires.append('setuptools_darcs >= 1.1.0')
156 # trialcoverage is required if you want the "trial" unit test runner to have a
157 # "--reporter=bwverbose-coverage" option which produces code-coverage results.
158 # The required version is 0.3.3, because that is the latest version that only
159 # depends on a version of pycoverage for which binary packages are available.
160 if "--reporter=bwverbose-coverage" in sys.argv:
161 setup_requires.append('trialcoverage >= 0.3.3')
163 # stdeb is required to produce Debian files with the "sdist_dsc" command.
164 if "sdist_dsc" in sys.argv:
165 setup_requires.append('stdeb >= 0.3')
168 # Mock - Mocking and Testing Library
169 # http://www.voidspace.org.uk/python/mock/
173 class ShowSupportLib(Command):
175 def initialize_options(self):
177 def finalize_options(self):
180 # TODO: --quiet suppresses the 'running show_supportlib' message.
181 # Find a way to do this all the time.
182 print supportlib # TODO windowsy
184 class ShowPythonPath(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 "PYTHONPATH=%s" % os.environ.get("PYTHONPATH", '')
195 class RunWithPythonPath(Command):
196 description = "Run a subcommand with PYTHONPATH set appropriately"
198 user_options = [ ("python", "p",
199 "Treat command string as arguments to a python executable"),
200 ("command=", "c", "Command to be run"),
201 ("directory=", "d", "Directory to run the command in"),
203 boolean_options = ["python"]
205 def initialize_options(self):
208 self.directory = None
209 def finalize_options(self):
212 oldpp = os.environ.get("PYTHONPATH", "").split(os.pathsep)
214 # grr silly split() behavior
216 os.environ['PYTHONPATH'] = os.pathsep.join(oldpp + [supportlib,])
218 # We must require the command to be safe to split on
219 # whitespace, and have --python and --directory to make it
220 # easier to achieve this.
224 command.append(sys.executable)
226 command.extend(self.command.split())
228 raise RuntimeError("The --command argument is mandatory")
230 os.chdir(self.directory)
232 print "command =", " ".join(command)
233 rc = subprocess.call(command)
236 class TestMacDiskImage(Command):
238 def initialize_options(self):
240 def finalize_options(self):
244 sys.path.append(os.path.join('misc', 'build_helpers'))
245 import test_mac_diskimage
246 return test_mac_diskimage.test_mac_diskimage('Allmydata', version=self.distribution.metadata.version)
248 class CheckAutoDeps(Command):
250 def initialize_options(self):
252 def finalize_options(self):
256 execfile('src/allmydata/_auto_deps.py', adglobals)
257 adglobals['require_auto_deps']()
260 class MakeExecutable(Command):
262 def initialize_options(self):
264 def finalize_options(self):
267 bin_tahoe_template = os.path.join("bin", "tahoe-script.template")
269 if sys.platform == 'win32':
270 # 'tahoe' script is needed for cygwin
271 script_names = ["tahoe.pyscript", "tahoe"]
273 script_names = ["tahoe"]
275 # Create the tahoe script file under the 'bin' directory. This
276 # file is exactly the same as the 'tahoe-script.template' script
277 # except that the shebang line is rewritten to use our sys.executable
278 # for the interpreter.
279 f = open(bin_tahoe_template, "rU")
280 script_lines = f.readlines()
282 script_lines[0] = '#!%s\n' % (sys.executable,)
283 for script_name in script_names:
284 tahoe_script = os.path.join("bin", script_name)
286 os.remove(tahoe_script)
288 if os.path.exists(tahoe_script):
290 f = open(tahoe_script, "wb")
291 for line in script_lines:
296 old_mode = stat.S_IMODE(os.stat(tahoe_script)[stat.ST_MODE])
297 new_mode = old_mode | (stat.S_IXUSR | stat.S_IRUSR |
298 stat.S_IXGRP | stat.S_IRGRP |
299 stat.S_IXOTH | stat.S_IROTH )
300 os.chmod(tahoe_script, new_mode)
302 old_tahoe_exe = os.path.join("bin", "tahoe.exe")
304 os.remove(old_tahoe_exe)
306 if os.path.exists(old_tahoe_exe):
310 class MySdist(sdist.sdist):
311 """ A hook in the sdist command so that we can determine whether this the
312 tarball should be 'SUMO' or not, i.e. whether or not to include the
313 external dependency tarballs. Note that we always include
314 misc/dependencies/* in the tarball; --sumo controls whether tahoe-deps/*
318 user_options = sdist.sdist.user_options + \
320 "create a 'sumo' sdist which includes the contents of tahoe-deps/*"),
322 boolean_options = ['sumo']
324 def initialize_options(self):
325 sdist.sdist.initialize_options(self)
328 def make_distribution(self):
329 # add our extra files to the list just before building the
330 # tarball/zipfile. We override make_distribution() instead of run()
331 # because setuptools.command.sdist.run() does not lend itself to
332 # easy/robust subclassing (the code we need to add goes right smack
333 # in the middle of a 12-line method). If this were the distutils
334 # version, we'd override get_file_list().
337 # If '--sumo' was specified, include tahoe-deps/* in the sdist.
338 # We assume that the user has fetched the tahoe-deps.tar.gz
339 # tarball and unpacked it already.
340 self.filelist.extend([os.path.join("tahoe-deps", fn)
341 for fn in os.listdir("tahoe-deps")])
342 # In addition, we want the tarball/zipfile to have -SUMO in the
343 # name, and the unpacked directory to have -SUMO too. The easiest
344 # way to do this is to patch self.distribution and override the
345 # get_fullname() method. (an alternative is to modify
346 # self.distribution.metadata.version, but that also affects the
347 # contents of PKG-INFO).
348 fullname = self.distribution.get_fullname()
350 return fullname + "-SUMO"
351 self.distribution.get_fullname = get_fullname
353 return sdist.sdist.make_distribution(self)
357 setup_args["version"] = version
360 description='secure, decentralized, fault-tolerant filesystem',
361 long_description=open('README.txt', 'rU').read(),
362 author='the Tahoe-LAFS project',
363 author_email='tahoe-dev@tahoe-lafs.org',
364 url='http://tahoe-lafs.org/',
365 license='GNU GPL', # see README.txt -- there is an alternative licence
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 tests_require=tests_require,
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.
384 versionfiles=['src/allmydata/_version.py',],