2 # -*- coding: utf-8 -*-
3 import sys; assert sys.version_info < (3,), ur"Tahoe-LAFS does not run under Python 3. Please use a version of Python between 2.6 and 2.7.x inclusive."
5 # Tahoe-LAFS -- secure, distributed storage grid
7 # Copyright © 2006-2012 The Tahoe-LAFS Software Foundation
9 # This file is part of Tahoe-LAFS.
11 # See the docs/about.rst file for licensing information.
13 import os, stat, subprocess, re
15 ##### sys.path management
17 def pylibdir(prefixdir):
18 pyver = "python%d.%d" % (sys.version_info[:2])
19 if sys.platform == "win32":
20 return os.path.join(prefixdir, "Lib", "site-packages")
22 return os.path.join(prefixdir, "lib", pyver, "site-packages")
24 basedir = os.path.dirname(os.path.abspath(__file__))
25 supportlib = pylibdir(os.path.join(basedir, "support"))
27 # locate our version number
29 def read_version_py(infname):
31 verstrline = open(infname, "rt").read()
32 except EnvironmentError:
35 VSRE = r"^verstr = ['\"]([^'\"]*)['\"]"
36 mo = re.search(VSRE, verstrline, re.M)
40 VERSION_PY_FILENAME = 'src/allmydata/_version.py'
41 VERSION_H_FILENAME = 'misc/build_helpers/windows/installer/installer/_version.h'
43 version = read_version_py(VERSION_PY_FILENAME)
45 APPNAME='allmydata-tahoe'
46 APPNAMEFILE = os.path.join('src', 'allmydata', '_appname.py')
47 APPNAMEFILESTR = "__appname__ = '%s'" % (APPNAME,)
49 curappnamefilestr = open(APPNAMEFILE, 'rU').read()
50 except EnvironmentError:
51 # No file, or unreadable or something, okay then let's try to write one.
52 open(APPNAMEFILE, "w").write(APPNAMEFILESTR)
54 if curappnamefilestr.strip() != APPNAMEFILESTR:
55 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))
58 # setuptools/zetuptoolz looks in __main__.__requires__ for a list of
59 # requirements. When running "python setup.py test", __main__ is
60 # setup.py, so we put the list here so that the requirements will be
61 # available for tests:
63 # Tahoe's dependencies are managed by the find_links= entry in setup.cfg and
64 # the _auto_deps.install_requires list, which is used in the call to setup()
67 execfile('src/allmydata/_auto_deps.py', adglobals)
68 install_requires = adglobals['install_requires']
70 if len(sys.argv) > 1 and sys.argv[1] == '--fakedependency':
72 install_requires += ["fakedependency >= 1.0.0"]
74 __requires__ = install_requires[:]
76 egg = os.path.realpath('setuptools-0.6c16dev5.egg')
77 sys.path.insert(0, egg)
78 import setuptools; setuptools.bootstrap_install_from = egg
80 from setuptools import setup
81 from setuptools.command import sdist
82 from setuptools import Command
85 "Development Status :: 5 - Production/Stable",
86 "Environment :: Console",
87 "Environment :: Web Environment",
88 "License :: OSI Approved :: GNU General Public License (GPL)",
89 "License :: DFSG approved",
90 "License :: Other/Proprietary License",
91 "Intended Audience :: Developers",
92 "Intended Audience :: End Users/Desktop",
93 "Intended Audience :: System Administrators",
94 "Operating System :: Microsoft",
95 "Operating System :: Microsoft :: Windows",
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.6",
106 "Programming Language :: Python :: 2.7",
107 "Topic :: Utilities",
108 "Topic :: System :: Systems Administration",
109 "Topic :: System :: Filesystems",
110 "Topic :: System :: Distributed Computing",
111 "Topic :: Software Development :: Libraries",
112 "Topic :: System :: Archiving :: Backup",
113 "Topic :: System :: Archiving :: Mirroring",
114 "Topic :: System :: Archiving",
120 # Nevow imports itself when building, which causes Twisted and zope.interface
121 # to be imported. We need to make sure that the versions of Twisted and
122 # zope.interface used at build time satisfy Nevow's requirements. If not
123 # then there are two problems:
124 # - prior to Nevow v0.9.33, Nevow didn't declare its dependency on Twisted
125 # in a way that enabled setuptools to satisfy that requirement at
127 # - some versions of zope.interface, e.g. v3.6.4, are incompatible with
128 # Nevow, and we need to avoid those both at build and run-time.
130 # This only matters when compatible versions of Twisted and zope.interface
131 # are not already installed. Retire this hack when
132 # https://bugs.launchpad.net/nevow/+bug/812537 has been fixed.
133 setup_requires += [req for req in install_requires if req.startswith('Twisted') or req.startswith('zope.interface')]
135 # We no longer have any requirements specific to tests.
139 class Trial(Command):
140 description = "run trial (use 'bin%stahoe debug trial' for the full set of trial options)" % (os.sep,)
141 # This is just a subset of the most useful options, for compatibility.
142 user_options = [ ("no-rterrors", None, "Don't print out tracebacks as they occur."),
143 ("rterrors", "e", "Print out tracebacks as they occur (default, so ignored)."),
144 ("until-failure", "u", "Repeat a test (specified by -s) until it fails."),
145 ("reporter=", None, "The reporter to use for this test run."),
146 ("suite=", "s", "Specify the test suite."),
147 ("quiet", None, "Don't display version numbers and paths of Tahoe dependencies."),
148 ("coverage", "c", "Collect branch coverage information."),
151 def initialize_options(self):
152 self.rterrors = False
153 self.no_rterrors = False
154 self.until_failure = False
156 self.suite = "allmydata"
158 self.coverage = False
160 def finalize_options(self):
164 args = [sys.executable, os.path.join('bin', 'tahoe')]
167 from errno import ENOENT
168 coverage_cmd = 'coverage'
170 subprocess.call([coverage_cmd, 'help'])
172 if e.errno != ENOENT:
174 coverage_cmd = 'python-coverage'
176 rc = subprocess.call([coverage_cmd, 'help'])
178 if e.errno != ENOENT:
181 print >>sys.stderr, "Couldn't find the command 'coverage' nor 'python-coverage'."
182 print >>sys.stderr, "coverage can be installed using 'pip install coverage', or on Debian-based systems, 'apt-get install python-coverage'."
185 args += ['@' + coverage_cmd, 'run', '--branch', '--source=src/allmydata', '@tahoe']
188 args.append('--version-and-path')
189 args += ['debug', 'trial']
190 if self.rterrors and self.no_rterrors:
191 raise AssertionError("--rterrors and --no-rterrors conflict.")
192 if not self.no_rterrors:
193 args.append('--rterrors')
194 if self.until_failure:
195 args.append('--until-failure')
197 args.append('--reporter=' + self.reporter)
199 args.append(self.suite)
200 rc = subprocess.call(args)
204 class MakeExecutable(Command):
205 description = "make the 'bin%stahoe' scripts" % (os.sep,)
208 def initialize_options(self):
210 def finalize_options(self):
213 bin_tahoe_template = os.path.join("bin", "tahoe-script.template")
215 # tahoe.pyscript is really only necessary for Windows, but we also
216 # create it on Unix for consistency.
217 script_names = ["tahoe.pyscript", "tahoe"]
219 # Create the tahoe script file under the 'bin' directory. This
220 # file is exactly the same as the 'tahoe-script.template' script
221 # except that the shebang line is rewritten to use our sys.executable
222 # for the interpreter.
223 f = open(bin_tahoe_template, "rU")
224 script_lines = f.readlines()
226 script_lines[0] = '#!%s\n' % (sys.executable,)
227 for script_name in script_names:
228 tahoe_script = os.path.join("bin", script_name)
230 os.remove(tahoe_script)
232 if os.path.exists(tahoe_script):
234 f = open(tahoe_script, "wb")
235 for line in script_lines:
240 unix_script = os.path.join("bin", "tahoe")
241 old_mode = stat.S_IMODE(os.stat(unix_script)[stat.ST_MODE])
242 new_mode = old_mode | (stat.S_IXUSR | stat.S_IRUSR |
243 stat.S_IXGRP | stat.S_IRGRP |
244 stat.S_IXOTH | stat.S_IROTH )
245 os.chmod(unix_script, new_mode)
247 old_tahoe_exe = os.path.join("bin", "tahoe.exe")
249 os.remove(old_tahoe_exe)
251 if os.path.exists(old_tahoe_exe):
256 # This _version.py is generated from git metadata by the tahoe setup.py.
258 __pkgname__ = %(pkgname)r
259 real_version = %(version)r
260 full_version = %(full)r
262 verstr = %(normalized)r
267 // This _version.h is generated from git metadata by the tahoe setup.py.
269 #define PKGNAME_AND_VERSION L"%(pkgname)s-%(normalized)s"
272 def run_command(args, cwd=None):
274 # remember shell=False, so use git.cmd on windows, not just git
275 p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd)
276 except EnvironmentError as e: # if this gives a SyntaxError, note that Tahoe-LAFS requires Python 2.6+
277 print("Warning: unable to run %r." % (" ".join(args),))
280 stdout = p.communicate()[0].strip()
281 if p.returncode != 0:
282 print("Warning: %r returned error code %r." % (" ".join(args), p.returncode))
287 def versions_from_git(tag_prefix):
288 # This runs 'git' from the directory that contains this file. That either
289 # means someone ran a setup.py command (and this code is in
290 # versioneer.py, thus the containing directory is the root of the source
291 # tree), or someone ran a project-specific entry point (and this code is
292 # in _version.py, thus the containing directory is somewhere deeper in
293 # the source tree). This only gets called if the git-archive 'subst'
294 # variables were *not* expanded, and _version.py hasn't already been
295 # rewritten with a short version string, meaning we're inside a checked
298 # versions_from_git (as copied from python-versioneer) returns strings
299 # like "1.9.0-25-gb73aba9-dirty", which means we're in a tree with
300 # uncommited changes (-dirty), the latest checkin is revision b73aba9,
301 # the most recent tag was 1.9.0, and b73aba9 has 25 commits that weren't
302 # in 1.9.0 . The narrow-minded NormalizedVersion parser that takes our
303 # output (meant to enable sorting of version strings) refuses most of
304 # that. Tahoe uses a function named suggest_normalized_version() that can
305 # handle "1.9.0.post25", so dumb down our output to match.
308 source_dir = os.path.dirname(os.path.abspath(__file__))
309 except NameError as e:
310 # some py2exe/bbfreeze/non-CPython implementations don't do __file__
311 print("Warning: unable to find version because we could not obtain the source directory.")
315 if sys.platform == "win32":
317 stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"],
320 # run_command already complained.
322 if not stdout.startswith(tag_prefix):
323 print("Warning: tag %r doesn't start with prefix %r." % (stdout, tag_prefix))
325 version = stdout[len(tag_prefix):]
326 pieces = version.split("-")
328 normalized_version = pieces[0]
330 normalized_version = "%s.post%s" % (pieces[0], pieces[1])
332 stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=source_dir)
334 # run_command already complained.
336 full = stdout.strip()
337 if version.endswith("-dirty"):
339 normalized_version += ".dev0"
341 # Thanks to Jistanidiot at <http://stackoverflow.com/questions/6245570/get-current-branch-name>.
342 stdout = run_command([GIT, "rev-parse", "--abbrev-ref", "HEAD"], cwd=source_dir)
343 branch = (stdout or "unknown").strip()
345 return {"version": version, "normalized": normalized_version, "full": full, "branch": branch}
347 # setup.cfg has an [aliases] section which runs "update_version" before many
348 # commands (like "build" and "sdist") that need to know our package version
349 # ahead of time. If you add different commands (or if we forgot some), you
350 # may need to add it to setup.cfg and configure it to run update_version
351 # before your command.
353 class UpdateVersion(Command):
354 description = "update _version.py from revision-control metadata"
357 def initialize_options(self):
359 def finalize_options(self):
364 if os.path.isdir(os.path.join(basedir, ".git")):
365 verstr = self.try_from_git()
368 self.distribution.metadata.version = verstr
371 ********************************************************************
372 Warning: no version information found. This may cause tests to fail.
373 ********************************************************************
376 def try_from_git(self):
377 # If we change APPNAME, the release tag names should also change from then on.
378 versions = versions_from_git(APPNAME + '-')
381 "pkgname": self.distribution.get_name(),
382 "version": versions["version"],
383 "normalized": versions["normalized"],
384 "full": versions["full"],
385 "branch": versions["branch"],
388 f = open(VERSION_PY_FILENAME, "wb")
389 f.write(GIT_VERSION_PY % version_info)
391 print("Wrote normalized version %r into '%s'" % (versions["normalized"], VERSION_PY_FILENAME))
393 f = open(VERSION_H_FILENAME, "wb")
394 f.write(GIT_VERSION_H % version_info)
397 return versions.get("normalized", None)
400 class MySdist(sdist.sdist):
401 """ A hook in the sdist command so that we can determine whether this the
402 tarball should be 'SUMO' or not, i.e. whether or not to include the
403 external dependency tarballs. Note that we always include
404 misc/dependencies/* in the tarball; --sumo controls whether tahoe-deps/*
408 user_options = sdist.sdist.user_options + \
410 "create a 'sumo' sdist which includes the contents of tahoe-deps/*"),
412 boolean_options = ['sumo']
414 def initialize_options(self):
415 sdist.sdist.initialize_options(self)
418 def make_distribution(self):
419 # add our extra files to the list just before building the
420 # tarball/zipfile. We override make_distribution() instead of run()
421 # because setuptools.command.sdist.run() does not lend itself to
422 # easy/robust subclassing (the code we need to add goes right smack
423 # in the middle of a 12-line method). If this were the distutils
424 # version, we'd override get_file_list().
427 # If '--sumo' was specified, include tahoe-deps/* in the sdist.
428 # We assume that the user has fetched the tahoe-deps.tar.gz
429 # tarball and unpacked it already.
430 self.filelist.extend([os.path.join("tahoe-deps", fn)
431 for fn in os.listdir("tahoe-deps")])
432 # In addition, we want the tarball/zipfile to have -SUMO in the
433 # name, and the unpacked directory to have -SUMO too. The easiest
434 # way to do this is to patch self.distribution and override the
435 # get_fullname() method. (an alternative is to modify
436 # self.distribution.metadata.version, but that also affects the
437 # contents of PKG-INFO).
438 fullname = self.distribution.get_fullname()
440 return fullname + "-SUMO"
441 self.distribution.get_fullname = get_fullname
444 old_mask = os.umask(int("022", 8))
445 return sdist.sdist.make_distribution(self)
452 setup_args["version"] = version
455 description='secure, decentralized, fault-tolerant filesystem',
456 long_description=open('README.rst', 'rU').read(),
457 author='the Tahoe-LAFS project',
458 author_email='tahoe-dev@tahoe-lafs.org',
459 url='https://tahoe-lafs.org/',
460 license='GNU GPL', # see README.rst -- there is an alternative licence
461 cmdclass={"trial": Trial,
462 "make_executable": MakeExecutable,
463 "update_version": UpdateVersion,
466 package_dir = {'':'src'},
467 packages=['allmydata',
468 'allmydata.frontends',
469 'allmydata.immutable',
470 'allmydata.immutable.downloader',
471 'allmydata.introducer',
480 classifiers=trove_classifiers,
481 test_suite="allmydata.test",
482 install_requires=install_requires,
483 tests_require=tests_require,
484 package_data={"allmydata.web": ["*.xhtml",
485 "static/*.js", "static/*.png", "static/*.css",
490 setup_requires=setup_requires,
491 entry_points = { 'console_scripts': [ 'tahoe = allmydata.scripts.runner:run' ] },
492 zip_safe=False, # We prefer unzipped for easier access.