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 if len(sys.argv) > 1 and sys.argv[1] == '--fakedependency':
68 install_requires += ["fakedependency >= 1.0.0"]
70 __requires__ = install_requires[:]
71 if 'trial' in sys.argv or 'test' in sys.argv:
72 if version is not None:
73 __requires__.append(APPNAME + '==' + version)
75 __requires__.append(APPNAME)
77 egg = os.path.realpath(glob.glob('setuptools-*.egg')[0])
78 sys.path.insert(0, egg)
79 egg = os.path.realpath(glob.glob('darcsver-*.egg')[0])
80 sys.path.insert(0, egg)
81 egg = os.path.realpath(glob.glob('setuptools_darcs-*.egg')[0])
82 sys.path.insert(0, egg)
83 import setuptools; setuptools.bootstrap_install_from = egg
85 from setuptools import find_packages, setup
86 from setuptools.command import sdist
87 from setuptools import Command
90 "Development Status :: 5 - Production/Stable",
91 "Environment :: Console",
92 "Environment :: Web Environment",
93 "License :: OSI Approved :: GNU General Public License (GPL)",
94 "License :: DFSG approved",
95 "License :: Other/Proprietary License",
96 "Intended Audience :: Developers",
97 "Intended Audience :: End Users/Desktop",
98 "Intended Audience :: System Administrators",
99 "Operating System :: Microsoft",
100 "Operating System :: Microsoft :: Windows",
101 "Operating System :: Microsoft :: Windows :: Windows NT/2000",
102 "Operating System :: Unix",
103 "Operating System :: POSIX :: Linux",
104 "Operating System :: POSIX",
105 "Operating System :: MacOS :: MacOS X",
106 "Operating System :: OS Independent",
107 "Natural Language :: English",
108 "Programming Language :: C",
109 "Programming Language :: Python",
110 "Programming Language :: Python :: 2",
111 "Programming Language :: Python :: 2.4",
112 "Programming Language :: Python :: 2.5",
113 "Programming Language :: Python :: 2.6",
114 "Programming Language :: Python :: 2.7",
115 "Topic :: Utilities",
116 "Topic :: System :: Systems Administration",
117 "Topic :: System :: Filesystems",
118 "Topic :: System :: Distributed Computing",
119 "Topic :: Software Development :: Libraries",
120 "Topic :: Communications :: Usenet News",
121 "Topic :: System :: Archiving :: Backup",
122 "Topic :: System :: Archiving :: Mirroring",
123 "Topic :: System :: Archiving",
129 # The darcsver command from the darcsver plugin is needed to initialize the
130 # distribution's .version attribute correctly. (It does this either by
131 # examining darcs history, or if that fails by reading the
132 # src/allmydata/_version.py file). darcsver will also write a new version
133 # stamp in src/allmydata/_version.py, with a version number derived from
134 # darcs history. Note that the setup.cfg file has an "[aliases]" section
135 # which enumerates commands that you might run and specifies that it will run
136 # darcsver before each one. If you add different commands (or if I forgot
137 # some that are already in use), you may need to add it to setup.cfg and
138 # configure it to run darcsver before your command, if you want the version
139 # number to be correct when that command runs.
140 # http://pypi.python.org/pypi/darcsver
141 setup_requires.append('darcsver >= 1.7.1')
143 # Nevow requires Twisted to setup, but doesn't declare that requirement in a
144 # way that enables setuptools to satisfy that requirement before Nevow's
145 # setup.py tried to "import twisted". Fortunately we require setuptools_trial
146 # to setup and setuptools_trial requires Twisted to install, so hopefully
147 # everything will work out until the Nevow issue is fixed:
148 # http://divmod.org/trac/ticket/2629 setuptools_trial is needed if you want
149 # "./setup.py trial" or "./setup.py test" to execute the tests (and in order
150 # to make sure Twisted is installed early enough -- see the paragraph above).
151 # http://pypi.python.org/pypi/setuptools_trial
152 setup_requires.extend(['setuptools_trial >= 0.5'])
154 # setuptools_darcs is required to produce complete distributions (such
155 # as with "sdist" or "bdist_egg"), unless there is a
156 # src/allmydata_tahoe.egg-info/SOURCE.txt file, which if present
157 # contains a complete list of files that should be included.
158 # http://pypi.python.org/pypi/setuptools_darcs
159 setup_requires.append('setuptools_darcs >= 1.1.0')
161 # trialcoverage is required if you want the "trial" unit test runner to have a
162 # "--reporter=bwverbose-coverage" option which produces code-coverage results.
163 # The required version is 0.3.3, because that is the latest version that only
164 # depends on a version of pycoverage for which binary packages are available.
165 if "--reporter=bwverbose-coverage" in sys.argv:
166 setup_requires.append('trialcoverage >= 0.3.3')
168 # stdeb is required to produce Debian files with the "sdist_dsc" command.
169 if "sdist_dsc" in sys.argv:
170 setup_requires.append('stdeb >= 0.3')
173 # Mock - Mocking and Testing Library
174 # http://www.voidspace.org.uk/python/mock/
178 class ShowSupportLib(Command):
180 def initialize_options(self):
182 def finalize_options(self):
185 # TODO: --quiet suppresses the 'running show_supportlib' message.
186 # Find a way to do this all the time.
187 print supportlib # TODO windowsy
189 class ShowPythonPath(Command):
191 def initialize_options(self):
193 def finalize_options(self):
196 # TODO: --quiet suppresses the 'running show_supportlib' message.
197 # Find a way to do this all the time.
198 print "PYTHONPATH=%s" % os.environ.get("PYTHONPATH", '')
200 class RunWithPythonPath(Command):
201 description = "Run a subcommand with PYTHONPATH set appropriately"
203 user_options = [ ("python", "p",
204 "Treat command string as arguments to a python executable"),
205 ("command=", "c", "Command to be run"),
206 ("directory=", "d", "Directory to run the command in"),
208 boolean_options = ["python"]
210 def initialize_options(self):
213 self.directory = None
214 def finalize_options(self):
217 oldpp = os.environ.get("PYTHONPATH", "").split(os.pathsep)
219 # grr silly split() behavior
221 os.environ['PYTHONPATH'] = os.pathsep.join(oldpp + [supportlib,])
223 # We must require the command to be safe to split on
224 # whitespace, and have --python and --directory to make it
225 # easier to achieve this.
229 command.append(sys.executable)
231 command.extend(self.command.split())
233 raise RuntimeError("The --command argument is mandatory")
235 os.chdir(self.directory)
237 print "command =", " ".join(command)
238 rc = subprocess.call(command)
241 class TestMacDiskImage(Command):
243 def initialize_options(self):
245 def finalize_options(self):
249 sys.path.append(os.path.join('misc', 'build_helpers'))
250 import test_mac_diskimage
251 return test_mac_diskimage.test_mac_diskimage('Allmydata', version=self.distribution.metadata.version)
253 class CheckAutoDeps(Command):
255 def initialize_options(self):
257 def finalize_options(self):
261 execfile('src/allmydata/_auto_deps.py', adglobals)
262 adglobals['require_auto_deps']()
265 class MakeExecutable(Command):
267 def initialize_options(self):
269 def finalize_options(self):
272 bin_tahoe_template = os.path.join("bin", "tahoe-script.template")
274 if sys.platform == 'win32':
275 # 'tahoe' script is needed for cygwin
276 script_names = ["tahoe.pyscript", "tahoe"]
278 script_names = ["tahoe"]
280 # Create the tahoe script file under the 'bin' directory. This
281 # file is exactly the same as the 'tahoe-script.template' script
282 # except that the shebang line is rewritten to use our sys.executable
283 # for the interpreter.
284 f = open(bin_tahoe_template, "rU")
285 script_lines = f.readlines()
287 script_lines[0] = '#!%s\n' % (sys.executable,)
288 for script_name in script_names:
289 tahoe_script = os.path.join("bin", script_name)
291 os.remove(tahoe_script)
293 if os.path.exists(tahoe_script):
295 f = open(tahoe_script, "wb")
296 for line in script_lines:
301 old_mode = stat.S_IMODE(os.stat(tahoe_script)[stat.ST_MODE])
302 new_mode = old_mode | (stat.S_IXUSR | stat.S_IRUSR |
303 stat.S_IXGRP | stat.S_IRGRP |
304 stat.S_IXOTH | stat.S_IROTH )
305 os.chmod(tahoe_script, new_mode)
307 old_tahoe_exe = os.path.join("bin", "tahoe.exe")
309 os.remove(old_tahoe_exe)
311 if os.path.exists(old_tahoe_exe):
315 class MySdist(sdist.sdist):
316 """ A hook in the sdist command so that we can determine whether this the
317 tarball should be 'SUMO' or not, i.e. whether or not to include the
318 external dependency tarballs. Note that we always include
319 misc/dependencies/* in the tarball; --sumo controls whether tahoe-deps/*
323 user_options = sdist.sdist.user_options + \
325 "create a 'sumo' sdist which includes the contents of tahoe-deps/*"),
327 boolean_options = ['sumo']
329 def initialize_options(self):
330 sdist.sdist.initialize_options(self)
333 def make_distribution(self):
334 # add our extra files to the list just before building the
335 # tarball/zipfile. We override make_distribution() instead of run()
336 # because setuptools.command.sdist.run() does not lend itself to
337 # easy/robust subclassing (the code we need to add goes right smack
338 # in the middle of a 12-line method). If this were the distutils
339 # version, we'd override get_file_list().
342 # If '--sumo' was specified, include tahoe-deps/* in the sdist.
343 # We assume that the user has fetched the tahoe-deps.tar.gz
344 # tarball and unpacked it already.
345 self.filelist.extend([os.path.join("tahoe-deps", fn)
346 for fn in os.listdir("tahoe-deps")])
347 # In addition, we want the tarball/zipfile to have -SUMO in the
348 # name, and the unpacked directory to have -SUMO too. The easiest
349 # way to do this is to patch self.distribution and override the
350 # get_fullname() method. (an alternative is to modify
351 # self.distribution.metadata.version, but that also affects the
352 # contents of PKG-INFO).
353 fullname = self.distribution.get_fullname()
355 return fullname + "-SUMO"
356 self.distribution.get_fullname = get_fullname
358 return sdist.sdist.make_distribution(self)
362 setup_args["version"] = version
365 description='secure, decentralized, fault-tolerant filesystem',
366 long_description=open('README.txt', 'rU').read(),
367 author='the Tahoe-LAFS project',
368 author_email='tahoe-dev@tahoe-lafs.org',
369 url='http://tahoe-lafs.org/',
370 license='GNU GPL', # see README.txt -- there is an alternative licence
371 cmdclass={"show_supportlib": ShowSupportLib,
372 "show_pythonpath": ShowPythonPath,
373 "run_with_pythonpath": RunWithPythonPath,
374 "check_auto_deps": CheckAutoDeps,
375 "test_mac_diskimage": TestMacDiskImage,
376 "make_executable": MakeExecutable,
379 package_dir = {'':'src'},
380 packages=find_packages("src"),
381 classifiers=trove_classifiers,
382 test_suite="allmydata.test",
383 install_requires=install_requires,
384 tests_require=tests_require,
385 include_package_data=True,
386 setup_requires=setup_requires,
387 entry_points = { 'console_scripts': [ 'tahoe = allmydata.scripts.runner:run' ] },
388 zip_safe=False, # We prefer unzipped for easier access.
389 versionfiles=['src/allmydata/_version.py',],