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 import setuptools; setuptools.bootstrap_install_from = egg
83 from setuptools import find_packages, setup
84 from setuptools.command import sdist
85 from setuptools import Command
88 "Development Status :: 5 - Production/Stable",
89 "Environment :: Console",
90 "Environment :: Web Environment",
91 "License :: OSI Approved :: GNU General Public License (GPL)",
92 "License :: DFSG approved",
93 "License :: Other/Proprietary License",
94 "Intended Audience :: Developers",
95 "Intended Audience :: End Users/Desktop",
96 "Intended Audience :: System Administrators",
97 "Operating System :: Microsoft",
98 "Operating System :: Microsoft :: Windows",
99 "Operating System :: Microsoft :: Windows :: Windows NT/2000",
100 "Operating System :: Unix",
101 "Operating System :: POSIX :: Linux",
102 "Operating System :: POSIX",
103 "Operating System :: MacOS :: MacOS X",
104 "Operating System :: OS Independent",
105 "Natural Language :: English",
106 "Programming Language :: C",
107 "Programming Language :: Python",
108 "Programming Language :: Python :: 2",
109 "Programming Language :: Python :: 2.4",
110 "Programming Language :: Python :: 2.5",
111 "Programming Language :: Python :: 2.6",
112 "Programming Language :: Python :: 2.7",
113 "Topic :: Utilities",
114 "Topic :: System :: Systems Administration",
115 "Topic :: System :: Filesystems",
116 "Topic :: System :: Distributed Computing",
117 "Topic :: Software Development :: Libraries",
118 "Topic :: Communications :: Usenet News",
119 "Topic :: System :: Archiving :: Backup",
120 "Topic :: System :: Archiving :: Mirroring",
121 "Topic :: System :: Archiving",
127 # The darcsver command from the darcsver plugin is needed to initialize the
128 # distribution's .version attribute correctly. (It does this either by
129 # examining darcs history, or if that fails by reading the
130 # src/allmydata/_version.py file). darcsver will also write a new version
131 # stamp in src/allmydata/_version.py, with a version number derived from
132 # darcs history. Note that the setup.cfg file has an "[aliases]" section
133 # which enumerates commands that you might run and specifies that it will run
134 # darcsver before each one. If you add different commands (or if I forgot
135 # some that are already in use), you may need to add it to setup.cfg and
136 # configure it to run darcsver before your command, if you want the version
137 # number to be correct when that command runs.
138 # http://pypi.python.org/pypi/darcsver
139 setup_requires.append('darcsver >= 1.7.1')
141 # Nevow requires Twisted to setup, but doesn't declare that requirement in a
142 # way that enables setuptools to satisfy that requirement before Nevow's
143 # setup.py tried to "import twisted". Fortunately we require setuptools_trial
144 # to setup and setuptools_trial requires Twisted to install, so hopefully
145 # everything will work out until the Nevow issue is fixed:
146 # http://divmod.org/trac/ticket/2629 setuptools_trial is needed if you want
147 # "./setup.py trial" or "./setup.py test" to execute the tests (and in order
148 # to make sure Twisted is installed early enough -- see the paragraph above).
149 # http://pypi.python.org/pypi/setuptools_trial
150 setup_requires.extend(['setuptools_trial >= 0.5'])
152 # setuptools_darcs is required to produce complete distributions (such as
153 # with "sdist" or "bdist_egg") (unless there is a PKG-INFO file present which
154 # shows that this is itself a source distribution). For simplicity, and
155 # because there is some unknown error with setuptools_darcs when building and
156 # testing tahoe all in one python command on some platforms, we always add it
157 # to setup_requires. http://pypi.python.org/pypi/setuptools_darcs
158 setup_requires.append('setuptools_darcs >= 1.1.0')
160 # trialcoverage is required if you want the "trial" unit test runner to have a
161 # "--reporter=bwverbose-coverage" option which produces code-coverage results.
162 # The required version is 0.3.3, because that is the latest version that only
163 # depends on a version of pycoverage for which binary packages are available.
164 if "--reporter=bwverbose-coverage" in sys.argv:
165 setup_requires.append('trialcoverage >= 0.3.3')
167 # stdeb is required to produce Debian files with the "sdist_dsc" command.
168 if "sdist_dsc" in sys.argv:
169 setup_requires.append('stdeb >= 0.3')
172 # Mock - Mocking and Testing Library
173 # http://www.voidspace.org.uk/python/mock/
177 class ShowSupportLib(Command):
179 def initialize_options(self):
181 def finalize_options(self):
184 # TODO: --quiet suppresses the 'running show_supportlib' message.
185 # Find a way to do this all the time.
186 print supportlib # TODO windowsy
188 class ShowPythonPath(Command):
190 def initialize_options(self):
192 def finalize_options(self):
195 # TODO: --quiet suppresses the 'running show_supportlib' message.
196 # Find a way to do this all the time.
197 print "PYTHONPATH=%s" % os.environ.get("PYTHONPATH", '')
199 class RunWithPythonPath(Command):
200 description = "Run a subcommand with PYTHONPATH set appropriately"
202 user_options = [ ("python", "p",
203 "Treat command string as arguments to a python executable"),
204 ("command=", "c", "Command to be run"),
205 ("directory=", "d", "Directory to run the command in"),
207 boolean_options = ["python"]
209 def initialize_options(self):
212 self.directory = None
213 def finalize_options(self):
216 oldpp = os.environ.get("PYTHONPATH", "").split(os.pathsep)
218 # grr silly split() behavior
220 os.environ['PYTHONPATH'] = os.pathsep.join(oldpp + [supportlib,])
222 # We must require the command to be safe to split on
223 # whitespace, and have --python and --directory to make it
224 # easier to achieve this.
228 command.append(sys.executable)
230 command.extend(self.command.split())
232 raise RuntimeError("The --command argument is mandatory")
234 os.chdir(self.directory)
236 print "command =", " ".join(command)
237 rc = subprocess.call(command)
240 class TestMacDiskImage(Command):
242 def initialize_options(self):
244 def finalize_options(self):
248 sys.path.append(os.path.join('misc', 'build_helpers'))
249 import test_mac_diskimage
250 return test_mac_diskimage.test_mac_diskimage('Allmydata', version=self.distribution.metadata.version)
252 class CheckAutoDeps(Command):
254 def initialize_options(self):
256 def finalize_options(self):
260 execfile('src/allmydata/_auto_deps.py', adglobals)
261 adglobals['require_auto_deps']()
264 class MakeExecutable(Command):
266 def initialize_options(self):
268 def finalize_options(self):
271 bin_tahoe_template = os.path.join("bin", "tahoe-script.template")
273 if sys.platform == 'win32':
274 # 'tahoe' script is needed for cygwin
275 script_names = ["tahoe.pyscript", "tahoe"]
277 script_names = ["tahoe"]
279 # Create the tahoe script file under the 'bin' directory. This
280 # file is exactly the same as the 'tahoe-script.template' script
281 # except that the shebang line is rewritten to use our sys.executable
282 # for the interpreter.
283 f = open(bin_tahoe_template, "rU")
284 script_lines = f.readlines()
286 script_lines[0] = '#!%s\n' % (sys.executable,)
287 for script_name in script_names:
288 tahoe_script = os.path.join("bin", script_name)
290 os.remove(tahoe_script)
292 if os.path.exists(tahoe_script):
294 f = open(tahoe_script, "wb")
295 for line in script_lines:
300 old_mode = stat.S_IMODE(os.stat(tahoe_script)[stat.ST_MODE])
301 new_mode = old_mode | (stat.S_IXUSR | stat.S_IRUSR |
302 stat.S_IXGRP | stat.S_IRGRP |
303 stat.S_IXOTH | stat.S_IROTH )
304 os.chmod(tahoe_script, new_mode)
306 old_tahoe_exe = os.path.join("bin", "tahoe.exe")
308 os.remove(old_tahoe_exe)
310 if os.path.exists(old_tahoe_exe):
314 class MySdist(sdist.sdist):
315 """ A hook in the sdist command so that we can determine whether this the
316 tarball should be 'SUMO' or not, i.e. whether or not to include the
317 external dependency tarballs. Note that we always include
318 misc/dependencies/* in the tarball; --sumo controls whether tahoe-deps/*
322 user_options = sdist.sdist.user_options + \
324 "create a 'sumo' sdist which includes the contents of tahoe-deps/*"),
326 boolean_options = ['sumo']
328 def initialize_options(self):
329 sdist.sdist.initialize_options(self)
332 def make_distribution(self):
333 # add our extra files to the list just before building the
334 # tarball/zipfile. We override make_distribution() instead of run()
335 # because setuptools.command.sdist.run() does not lend itself to
336 # easy/robust subclassing (the code we need to add goes right smack
337 # in the middle of a 12-line method). If this were the distutils
338 # version, we'd override get_file_list().
341 # If '--sumo' was specified, include tahoe-deps/* in the sdist.
342 # We assume that the user has fetched the tahoe-deps.tar.gz
343 # tarball and unpacked it already.
344 self.filelist.extend([os.path.join("tahoe-deps", fn)
345 for fn in os.listdir("tahoe-deps")])
346 # In addition, we want the tarball/zipfile to have -SUMO in the
347 # name, and the unpacked directory to have -SUMO too. The easiest
348 # way to do this is to patch self.distribution and override the
349 # get_fullname() method. (an alternative is to modify
350 # self.distribution.metadata.version, but that also affects the
351 # contents of PKG-INFO).
352 fullname = self.distribution.get_fullname()
354 return fullname + "-SUMO"
355 self.distribution.get_fullname = get_fullname
357 return sdist.sdist.make_distribution(self)
361 setup_args["version"] = version
364 description='secure, decentralized, fault-tolerant filesystem',
365 long_description=open('README.txt', 'rU').read(),
366 author='the Tahoe-LAFS project',
367 author_email='tahoe-dev@tahoe-lafs.org',
368 url='http://tahoe-lafs.org/',
369 license='GNU GPL', # see README.txt -- there is an alternative licence
370 cmdclass={"show_supportlib": ShowSupportLib,
371 "show_pythonpath": ShowPythonPath,
372 "run_with_pythonpath": RunWithPythonPath,
373 "check_auto_deps": CheckAutoDeps,
374 "test_mac_diskimage": TestMacDiskImage,
375 "make_executable": MakeExecutable,
378 package_dir = {'':'src'},
379 packages=find_packages("src"),
380 classifiers=trove_classifiers,
381 test_suite="allmydata.test",
382 install_requires=install_requires,
383 tests_require=tests_require,
384 include_package_data=True,
385 setup_requires=setup_requires,
386 entry_points = { 'console_scripts': [ 'tahoe = allmydata.scripts.runner:run' ] },
387 zip_safe=False, # We prefer unzipped for easier access.
388 versionfiles=['src/allmydata/_version.py',],