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')
172 # We no longer have any requirements specific to tests.
176 class ShowSupportLib(Command):
178 def initialize_options(self):
180 def finalize_options(self):
183 # TODO: --quiet suppresses the 'running show_supportlib' message.
184 # Find a way to do this all the time.
185 print supportlib # TODO windowsy
187 class ShowPythonPath(Command):
189 def initialize_options(self):
191 def finalize_options(self):
194 # TODO: --quiet suppresses the 'running show_supportlib' message.
195 # Find a way to do this all the time.
196 print "PYTHONPATH=%s" % os.environ.get("PYTHONPATH", '')
198 class RunWithPythonPath(Command):
199 description = "Run a subcommand with PYTHONPATH set appropriately"
201 user_options = [ ("python", "p",
202 "Treat command string as arguments to a python executable"),
203 ("command=", "c", "Command to be run"),
204 ("directory=", "d", "Directory to run the command in"),
206 boolean_options = ["python"]
208 def initialize_options(self):
211 self.directory = None
212 def finalize_options(self):
215 oldpp = os.environ.get("PYTHONPATH", "").split(os.pathsep)
217 # grr silly split() behavior
219 os.environ['PYTHONPATH'] = os.pathsep.join(oldpp + [supportlib,])
221 # We must require the command to be safe to split on
222 # whitespace, and have --python and --directory to make it
223 # easier to achieve this.
227 command.append(sys.executable)
229 command.extend(self.command.split())
231 raise RuntimeError("The --command argument is mandatory")
233 os.chdir(self.directory)
235 print "command =", " ".join(command)
236 rc = subprocess.call(command)
239 class TestMacDiskImage(Command):
241 def initialize_options(self):
243 def finalize_options(self):
247 sys.path.append(os.path.join('misc', 'build_helpers'))
248 import test_mac_diskimage
249 return test_mac_diskimage.test_mac_diskimage('Allmydata', version=self.distribution.metadata.version)
251 class CheckAutoDeps(Command):
253 def initialize_options(self):
255 def finalize_options(self):
259 execfile('src/allmydata/_auto_deps.py', adglobals)
260 adglobals['require_auto_deps']()
263 class MakeExecutable(Command):
265 def initialize_options(self):
267 def finalize_options(self):
270 bin_tahoe_template = os.path.join("bin", "tahoe-script.template")
272 if sys.platform == 'win32':
273 # 'tahoe' script is needed for cygwin
274 script_names = ["tahoe.pyscript", "tahoe"]
276 script_names = ["tahoe"]
278 # Create the tahoe script file under the 'bin' directory. This
279 # file is exactly the same as the 'tahoe-script.template' script
280 # except that the shebang line is rewritten to use our sys.executable
281 # for the interpreter.
282 f = open(bin_tahoe_template, "rU")
283 script_lines = f.readlines()
285 script_lines[0] = '#!%s\n' % (sys.executable,)
286 for script_name in script_names:
287 tahoe_script = os.path.join("bin", script_name)
289 os.remove(tahoe_script)
291 if os.path.exists(tahoe_script):
293 f = open(tahoe_script, "wb")
294 for line in script_lines:
299 old_mode = stat.S_IMODE(os.stat(tahoe_script)[stat.ST_MODE])
300 new_mode = old_mode | (stat.S_IXUSR | stat.S_IRUSR |
301 stat.S_IXGRP | stat.S_IRGRP |
302 stat.S_IXOTH | stat.S_IROTH )
303 os.chmod(tahoe_script, new_mode)
305 old_tahoe_exe = os.path.join("bin", "tahoe.exe")
307 os.remove(old_tahoe_exe)
309 if os.path.exists(old_tahoe_exe):
313 class MySdist(sdist.sdist):
314 """ A hook in the sdist command so that we can determine whether this the
315 tarball should be 'SUMO' or not, i.e. whether or not to include the
316 external dependency tarballs. Note that we always include
317 misc/dependencies/* in the tarball; --sumo controls whether tahoe-deps/*
321 user_options = sdist.sdist.user_options + \
323 "create a 'sumo' sdist which includes the contents of tahoe-deps/*"),
325 boolean_options = ['sumo']
327 def initialize_options(self):
328 sdist.sdist.initialize_options(self)
331 def make_distribution(self):
332 # add our extra files to the list just before building the
333 # tarball/zipfile. We override make_distribution() instead of run()
334 # because setuptools.command.sdist.run() does not lend itself to
335 # easy/robust subclassing (the code we need to add goes right smack
336 # in the middle of a 12-line method). If this were the distutils
337 # version, we'd override get_file_list().
340 # If '--sumo' was specified, include tahoe-deps/* in the sdist.
341 # We assume that the user has fetched the tahoe-deps.tar.gz
342 # tarball and unpacked it already.
343 self.filelist.extend([os.path.join("tahoe-deps", fn)
344 for fn in os.listdir("tahoe-deps")])
345 # In addition, we want the tarball/zipfile to have -SUMO in the
346 # name, and the unpacked directory to have -SUMO too. The easiest
347 # way to do this is to patch self.distribution and override the
348 # get_fullname() method. (an alternative is to modify
349 # self.distribution.metadata.version, but that also affects the
350 # contents of PKG-INFO).
351 fullname = self.distribution.get_fullname()
353 return fullname + "-SUMO"
354 self.distribution.get_fullname = get_fullname
356 return sdist.sdist.make_distribution(self)
360 setup_args["version"] = version
363 description='secure, decentralized, fault-tolerant filesystem',
364 long_description=open('README.txt', 'rU').read(),
365 author='the Tahoe-LAFS project',
366 author_email='tahoe-dev@tahoe-lafs.org',
367 url='http://tahoe-lafs.org/',
368 license='GNU GPL', # see README.txt -- there is an alternative licence
369 cmdclass={"show_supportlib": ShowSupportLib,
370 "show_pythonpath": ShowPythonPath,
371 "run_with_pythonpath": RunWithPythonPath,
372 "check_auto_deps": CheckAutoDeps,
373 "test_mac_diskimage": TestMacDiskImage,
374 "make_executable": MakeExecutable,
377 package_dir = {'':'src'},
378 packages=find_packages("src"),
379 classifiers=trove_classifiers,
380 test_suite="allmydata.test",
381 install_requires=install_requires,
382 tests_require=tests_require,
383 include_package_data=True,
384 setup_requires=setup_requires,
385 entry_points = { 'console_scripts': [ 'tahoe = allmydata.scripts.runner:run' ] },
386 zip_safe=False, # We prefer unzipped for easier access.
387 versionfiles=['src/allmydata/_version.py',],