2 # -*- coding: utf-8 -*-
3 import sys; assert sys.version_info < (3,), ur"Tahoe-LAFS does not run under Python 3. Please use Python 2.7.x."
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 = read_version_py(VERSION_PY_FILENAME)
43 APPNAME='allmydata-tahoe'
44 APPNAMEFILE = os.path.join('src', 'allmydata', '_appname.py')
45 APPNAMEFILESTR = "__appname__ = '%s'" % (APPNAME,)
47 curappnamefilestr = open(APPNAMEFILE, 'rU').read()
48 except EnvironmentError:
49 # No file, or unreadable or something, okay then let's try to write one.
50 open(APPNAMEFILE, "w").write(APPNAMEFILESTR)
52 if curappnamefilestr.strip() != APPNAMEFILESTR:
53 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))
56 # setuptools looks in __main__.__requires__ for a list of
57 # requirements. When running "python setup.py test", __main__ is
58 # setup.py, so we put the list here so that the requirements will be
59 # available for tests:
61 # Tahoe's dependencies are managed by the find_links= entry in setup.cfg and
62 # the _auto_deps.install_requires list, which is used in the call to setup()
65 execfile('src/allmydata/_auto_deps.py', adglobals)
66 install_requires = adglobals['install_requires']
67 setup_requires = adglobals['setup_requires']
69 if len(sys.argv) > 1 and sys.argv[1] == '--fakedependency':
71 install_requires += ["fakedependency >= 1.0.0"]
73 __requires__ = install_requires[:]
77 from setuptools import setup
78 from setuptools.command import sdist
79 from setuptools import Command
82 "Development Status :: 5 - Production/Stable",
83 "Environment :: Console",
84 "Environment :: Web Environment",
85 "License :: OSI Approved :: GNU General Public License (GPL)",
86 "License :: DFSG approved",
87 "License :: Other/Proprietary License",
88 "Intended Audience :: Developers",
89 "Intended Audience :: End Users/Desktop",
90 "Intended Audience :: System Administrators",
91 "Operating System :: Microsoft",
92 "Operating System :: Microsoft :: Windows",
93 "Operating System :: Unix",
94 "Operating System :: POSIX :: Linux",
95 "Operating System :: POSIX",
96 "Operating System :: MacOS :: MacOS X",
97 "Operating System :: OS Independent",
98 "Natural Language :: English",
99 "Programming Language :: C",
100 "Programming Language :: Python",
101 "Programming Language :: Python :: 2",
102 "Programming Language :: Python :: 2.7",
103 "Topic :: Utilities",
104 "Topic :: System :: Systems Administration",
105 "Topic :: System :: Filesystems",
106 "Topic :: System :: Distributed Computing",
107 "Topic :: Software Development :: Libraries",
108 "Topic :: System :: Archiving :: Backup",
109 "Topic :: System :: Archiving :: Mirroring",
110 "Topic :: System :: Archiving",
114 # We no longer have any requirements specific to tests.
118 class Trial(Command):
119 description = "run trial (use 'bin%stahoe debug trial' for the full set of trial options)" % (os.sep,)
120 # This is just a subset of the most useful options, for compatibility.
121 user_options = [ ("no-rterrors", None, "Don't print out tracebacks as they occur."),
122 ("rterrors", "e", "Print out tracebacks as they occur (default, so ignored)."),
123 ("until-failure", "u", "Repeat a test (specified by -s) until it fails."),
124 ("reporter=", None, "The reporter to use for this test run."),
125 ("suite=", "s", "Specify the test suite."),
126 ("quiet", None, "Don't display version numbers and paths of Tahoe dependencies."),
127 ("coverage", "c", "Collect branch coverage information."),
130 def initialize_options(self):
131 self.rterrors = False
132 self.no_rterrors = False
133 self.until_failure = False
135 self.suite = "allmydata"
137 self.coverage = False
139 def finalize_options(self):
143 args = [sys.executable, os.path.join('bin', 'tahoe')]
146 from errno import ENOENT
147 coverage_cmd = 'coverage'
149 subprocess.call([coverage_cmd, 'help'])
151 if e.errno != ENOENT:
153 coverage_cmd = 'python-coverage'
155 rc = subprocess.call([coverage_cmd, 'help'])
157 if e.errno != ENOENT:
160 print >>sys.stderr, "Couldn't find the command 'coverage' nor 'python-coverage'."
161 print >>sys.stderr, "coverage can be installed using 'pip install coverage', or on Debian-based systems, 'apt-get install python-coverage'."
164 args += ['@' + coverage_cmd, 'run', '--branch', '--source=src/allmydata', '@tahoe']
167 args.append('--version-and-path')
168 args += ['debug', 'trial']
169 if self.rterrors and self.no_rterrors:
170 raise AssertionError("--rterrors and --no-rterrors conflict.")
171 if not self.no_rterrors:
172 args.append('--rterrors')
173 if self.until_failure:
174 args.append('--until-failure')
176 args.append('--reporter=' + self.reporter)
178 args.append(self.suite)
179 rc = subprocess.call(args)
183 class MakeExecutable(Command):
184 description = "make the 'bin%stahoe' scripts" % (os.sep,)
187 def initialize_options(self):
189 def finalize_options(self):
192 bin_tahoe_template = os.path.join("bin", "tahoe-script.template")
194 # tahoe.pyscript is really only necessary for Windows, but we also
195 # create it on Unix for consistency.
196 script_names = ["tahoe.pyscript", "tahoe"]
198 # Create the tahoe script file under the 'bin' directory. This
199 # file is exactly the same as the 'tahoe-script.template' script
200 # except that the shebang line is rewritten to use our sys.executable
201 # for the interpreter.
202 f = open(bin_tahoe_template, "rU")
203 script_lines = f.readlines()
205 script_lines[0] = '#!%s\n' % (sys.executable,)
206 for script_name in script_names:
207 tahoe_script = os.path.join("bin", script_name)
209 os.remove(tahoe_script)
211 if os.path.exists(tahoe_script):
213 f = open(tahoe_script, "wb")
214 for line in script_lines:
219 unix_script = os.path.join("bin", "tahoe")
220 old_mode = stat.S_IMODE(os.stat(unix_script)[stat.ST_MODE])
221 new_mode = old_mode | (stat.S_IXUSR | stat.S_IRUSR |
222 stat.S_IXGRP | stat.S_IRGRP |
223 stat.S_IXOTH | stat.S_IROTH )
224 os.chmod(unix_script, new_mode)
226 old_tahoe_exe = os.path.join("bin", "tahoe.exe")
228 os.remove(old_tahoe_exe)
230 if os.path.exists(old_tahoe_exe):
234 GIT_VERSION_BODY = '''
235 # This _version.py is generated from git metadata by the tahoe setup.py.
237 __pkgname__ = %(pkgname)r
238 real_version = %(version)r
239 full_version = %(full)r
241 verstr = %(normalized)r
245 def run_command(args, cwd=None):
246 use_shell = sys.platform == "win32"
248 p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd, shell=use_shell)
249 except EnvironmentError as e: # if this gives a SyntaxError, note that Tahoe-LAFS requires Python 2.7+
250 print("Warning: unable to run %r." % (" ".join(args),))
253 stdout = p.communicate()[0].strip()
254 if p.returncode != 0:
255 print("Warning: %r returned error code %r." % (" ".join(args), p.returncode))
260 def versions_from_git(tag_prefix):
261 # This runs 'git' from the directory that contains this file. That either
262 # means someone ran a setup.py command (and this code is in
263 # versioneer.py, thus the containing directory is the root of the source
264 # tree), or someone ran a project-specific entry point (and this code is
265 # in _version.py, thus the containing directory is somewhere deeper in
266 # the source tree). This only gets called if the git-archive 'subst'
267 # variables were *not* expanded, and _version.py hasn't already been
268 # rewritten with a short version string, meaning we're inside a checked
271 # versions_from_git (as copied from python-versioneer) returns strings
272 # like "1.9.0-25-gb73aba9-dirty", which means we're in a tree with
273 # uncommited changes (-dirty), the latest checkin is revision b73aba9,
274 # the most recent tag was 1.9.0, and b73aba9 has 25 commits that weren't
275 # in 1.9.0 . The narrow-minded NormalizedVersion parser that takes our
276 # output (meant to enable sorting of version strings) refuses most of
277 # that. Tahoe uses a function named suggest_normalized_version() that can
278 # handle "1.9.0.post25", so dumb down our output to match.
281 source_dir = os.path.dirname(os.path.abspath(__file__))
282 except NameError as e:
283 # some py2exe/bbfreeze/non-CPython implementations don't do __file__
284 print("Warning: unable to find version because we could not obtain the source directory.")
287 stdout = run_command(["git", "describe", "--tags", "--dirty", "--always"],
290 # run_command already complained.
292 if not stdout.startswith(tag_prefix):
293 print("Warning: tag %r doesn't start with prefix %r." % (stdout, tag_prefix))
295 version = stdout[len(tag_prefix):]
296 pieces = version.split("-")
298 normalized_version = pieces[0]
300 normalized_version = "%s.post%s" % (pieces[0], pieces[1])
302 stdout = run_command(["git", "rev-parse", "HEAD"], cwd=source_dir)
304 # run_command already complained.
306 full = stdout.strip()
307 if version.endswith("-dirty"):
309 normalized_version += ".dev0"
311 # Thanks to Jistanidiot at <http://stackoverflow.com/questions/6245570/get-current-branch-name>.
312 stdout = run_command(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=source_dir)
313 branch = (stdout or "unknown").strip()
315 return {"version": version, "normalized": normalized_version, "full": full, "branch": branch}
317 # setup.cfg has an [aliases] section which runs "update_version" before many
318 # commands (like "build" and "sdist") that need to know our package version
319 # ahead of time. If you add different commands (or if we forgot some), you
320 # may need to add it to setup.cfg and configure it to run update_version
321 # before your command.
323 class UpdateVersion(Command):
324 description = "update _version.py from revision-control metadata"
327 def initialize_options(self):
329 def finalize_options(self):
334 if os.path.isdir(os.path.join(basedir, ".git")):
335 verstr = self.try_from_git()
338 self.distribution.metadata.version = verstr
341 ********************************************************************
342 Warning: no version information found. This may cause tests to fail.
343 ********************************************************************
346 def try_from_git(self):
347 # If we change APPNAME, the release tag names should also change from then on.
348 versions = versions_from_git(APPNAME + '-')
350 f = open(VERSION_PY_FILENAME, "wb")
351 f.write(GIT_VERSION_BODY %
352 { "pkgname": self.distribution.get_name(),
353 "version": versions["version"],
354 "normalized": versions["normalized"],
355 "full": versions["full"],
356 "branch": versions["branch"],
359 print("Wrote normalized version %r into '%s'" % (versions["normalized"], VERSION_PY_FILENAME))
361 return versions.get("normalized", None)
364 class MySdist(sdist.sdist):
365 """ A hook in the sdist command so that we can determine whether this the
366 tarball should be 'SUMO' or not, i.e. whether or not to include the
367 external dependency tarballs. Note that we always include
368 misc/dependencies/* in the tarball; --sumo controls whether tahoe-deps/*
372 user_options = sdist.sdist.user_options + \
374 "create a 'sumo' sdist which includes the contents of tahoe-deps/*"),
376 boolean_options = ['sumo']
378 def initialize_options(self):
379 sdist.sdist.initialize_options(self)
382 def make_distribution(self):
383 # add our extra files to the list just before building the
384 # tarball/zipfile. We override make_distribution() instead of run()
385 # because setuptools.command.sdist.run() does not lend itself to
386 # easy/robust subclassing (the code we need to add goes right smack
387 # in the middle of a 12-line method). If this were the distutils
388 # version, we'd override get_file_list().
391 # If '--sumo' was specified, include tahoe-deps/* in the sdist.
392 # We assume that the user has fetched the tahoe-deps.tar.gz
393 # tarball and unpacked it already.
394 self.filelist.extend([os.path.join("tahoe-deps", fn)
395 for fn in os.listdir("tahoe-deps")])
396 # In addition, we want the tarball/zipfile to have -SUMO in the
397 # name, and the unpacked directory to have -SUMO too. The easiest
398 # way to do this is to patch self.distribution and override the
399 # get_fullname() method. (an alternative is to modify
400 # self.distribution.metadata.version, but that also affects the
401 # contents of PKG-INFO).
402 fullname = self.distribution.get_fullname()
404 return fullname + "-SUMO"
405 self.distribution.get_fullname = get_fullname
408 old_mask = os.umask(int("022", 8))
409 return sdist.sdist.make_distribution(self)
416 setup_args["version"] = version
419 description='secure, decentralized, fault-tolerant file store',
420 long_description=open('README.rst', 'rU').read(),
421 author='the Tahoe-LAFS project',
422 author_email='tahoe-dev@tahoe-lafs.org',
423 url='https://tahoe-lafs.org/',
424 license='GNU GPL', # see README.rst -- there is an alternative licence
425 cmdclass={"trial": Trial,
426 "make_executable": MakeExecutable,
427 "update_version": UpdateVersion,
430 package_dir = {'':'src'},
431 packages=['allmydata',
432 'allmydata.frontends',
433 'allmydata.immutable',
434 'allmydata.immutable.downloader',
435 'allmydata.introducer',
444 classifiers=trove_classifiers,
445 test_suite="allmydata.test",
446 install_requires=install_requires,
447 tests_require=tests_require,
448 package_data={"allmydata.web": ["*.xhtml",
449 "static/*.js", "static/*.png", "static/*.css",
454 setup_requires=setup_requires,
455 entry_points = { 'console_scripts': [ 'tahoe = allmydata.scripts.runner:run' ] },
456 zip_safe=False, # We prefer unzipped for easier access.