]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - setup.py
remove obsolete debian-package building tools
[tahoe-lafs/tahoe-lafs.git] / setup.py
1 #! /usr/bin/env python
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."
4
5 # Tahoe-LAFS -- secure, distributed storage grid
6 #
7 # Copyright © 2006-2012 The Tahoe-LAFS Software Foundation
8 #
9 # This file is part of Tahoe-LAFS.
10 #
11 # See the docs/about.rst file for licensing information.
12
13 import glob, os, stat, subprocess, re
14
15 ##### sys.path management
16
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")
21     else:
22         return os.path.join(prefixdir, "lib", pyver, "site-packages")
23
24 basedir = os.path.dirname(os.path.abspath(__file__))
25 supportlib = pylibdir(os.path.join(basedir, "support"))
26
27 # locate our version number
28
29 def read_version_py(infname):
30     try:
31         verstrline = open(infname, "rt").read()
32     except EnvironmentError:
33         return None
34     else:
35         VSRE = r"^verstr = ['\"]([^'\"]*)['\"]"
36         mo = re.search(VSRE, verstrline, re.M)
37         if mo:
38             return mo.group(1)
39
40 version = read_version_py("src/allmydata/_version.py")
41
42 APPNAME='allmydata-tahoe'
43 APPNAMEFILE = os.path.join('src', 'allmydata', '_appname.py')
44 APPNAMEFILESTR = "__appname__ = '%s'" % (APPNAME,)
45 try:
46     curappnamefilestr = open(APPNAMEFILE, 'rU').read()
47 except EnvironmentError:
48     # No file, or unreadable or something, okay then let's try to write one.
49     open(APPNAMEFILE, "w").write(APPNAMEFILESTR)
50 else:
51     if curappnamefilestr.strip() != APPNAMEFILESTR:
52         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))
53         sys.exit(-1)
54
55 # setuptools/zetuptoolz looks in __main__.__requires__ for a list of
56 # requirements. When running "python setup.py test", __main__ is
57 # setup.py, so we put the list here so that the requirements will be
58 # available for tests:
59
60 # Tahoe's dependencies are managed by the find_links= entry in setup.cfg and
61 # the _auto_deps.install_requires list, which is used in the call to setup()
62 # below.
63 adglobals = {}
64 execfile('src/allmydata/_auto_deps.py', adglobals)
65 install_requires = adglobals['install_requires']
66
67 if len(sys.argv) > 1 and sys.argv[1] == '--fakedependency':
68     del sys.argv[1]
69     install_requires += ["fakedependency >= 1.0.0"]
70
71 __requires__ = install_requires[:]
72
73 egg = os.path.realpath(glob.glob('setuptools-*.egg')[0])
74 sys.path.insert(0, egg)
75 import setuptools; setuptools.bootstrap_install_from = egg
76
77 from setuptools import setup
78 from setuptools.command import sdist
79 from setuptools import Command
80
81 trove_classifiers=[
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 :: Microsoft :: Windows :: Windows NT/2000",
94     "Operating System :: Unix",
95     "Operating System :: POSIX :: Linux",
96     "Operating System :: POSIX",
97     "Operating System :: MacOS :: MacOS X",
98     "Operating System :: OS Independent",
99     "Natural Language :: English",
100     "Programming Language :: C",
101     "Programming Language :: Python",
102     "Programming Language :: Python :: 2",
103     "Programming Language :: Python :: 2.4",
104     "Programming Language :: Python :: 2.5",
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 :: Communications :: Usenet News",
113     "Topic :: System :: Archiving :: Backup",
114     "Topic :: System :: Archiving :: Mirroring",
115     "Topic :: System :: Archiving",
116     ]
117
118
119 setup_requires = []
120
121 # Nevow imports itself when building, which causes Twisted and zope.interface
122 # to be imported. We need to make sure that the versions of Twisted and
123 # zope.interface used at build time satisfy Nevow's requirements. If not
124 # then there are two problems:
125 #  - prior to Nevow v0.9.33, Nevow didn't declare its dependency on Twisted
126 #    in a way that enabled setuptools to satisfy that requirement at
127 #    build time.
128 #  - some versions of zope.interface, e.g. v3.6.4, are incompatible with
129 #    Nevow, and we need to avoid those both at build and run-time.
130 #
131 # This only matters when compatible versions of Twisted and zope.interface
132 # are not already installed. Retire this hack when
133 # https://bugs.launchpad.net/nevow/+bug/812537 has been fixed.
134 setup_requires += [req for req in install_requires if req.startswith('Twisted') or req.startswith('zope.interface')]
135
136 # trialcoverage is required if you want the "trial" unit test runner to have a
137 # "--reporter=bwverbose-coverage" option which produces code-coverage results.
138 # The required version is 0.3.3, because that is the latest version that only
139 # depends on a version of pycoverage for which binary packages are available.
140 if "--reporter=bwverbose-coverage" in sys.argv:
141     setup_requires.append('trialcoverage >= 0.3.3')
142
143 # We no longer have any requirements specific to tests.
144 tests_require=[]
145
146
147 class Trial(Command):
148     description = "run trial (use 'bin%stahoe debug trial' for the full set of trial options)" % (os.sep,)
149     # This is just a subset of the most useful options, for compatibility.
150     user_options = [ ("no-rterrors", None, "Don't print out tracebacks as they occur."),
151                      ("rterrors", "e", "Print out tracebacks as they occur (default, so ignored)."),
152                      ("until-failure", "u", "Repeat a test (specified by -s) until it fails."),
153                      ("reporter=", None, "The reporter to use for this test run."),
154                      ("suite=", "s", "Specify the test suite."),
155                      ("quiet", None, "Don't display version numbers and paths of Tahoe dependencies."),
156                    ]
157
158     def initialize_options(self):
159         self.rterrors = False
160         self.no_rterrors = False
161         self.until_failure = False
162         self.reporter = None
163         self.suite = "allmydata"
164         self.quiet = False
165
166     def finalize_options(self):
167         pass
168
169     def run(self):
170         args = [sys.executable, os.path.join('bin', 'tahoe')]
171         if not self.quiet:
172             args.append('--version-and-path')
173         args += ['debug', 'trial']
174         if self.rterrors and self.no_rterrors:
175             raise AssertionError("--rterrors and --no-rterrors conflict.")
176         if not self.no_rterrors:
177             args.append('--rterrors')
178         if self.until_failure:
179             args.append('--until-failure')
180         if self.reporter:
181             args.append('--reporter=' + self.reporter)
182         if self.suite:
183             args.append(self.suite)
184         rc = subprocess.call(args)
185         sys.exit(rc)
186
187
188 class MakeExecutable(Command):
189     description = "make the 'bin%stahoe' scripts" % (os.sep,)
190     user_options = []
191
192     def initialize_options(self):
193         pass
194     def finalize_options(self):
195         pass
196     def run(self):
197         bin_tahoe_template = os.path.join("bin", "tahoe-script.template")
198
199         # tahoe.pyscript is really only necessary for Windows, but we also
200         # create it on Unix for consistency.
201         script_names = ["tahoe.pyscript", "tahoe"]
202
203         # Create the tahoe script file under the 'bin' directory. This
204         # file is exactly the same as the 'tahoe-script.template' script
205         # except that the shebang line is rewritten to use our sys.executable
206         # for the interpreter.
207         f = open(bin_tahoe_template, "rU")
208         script_lines = f.readlines()
209         f.close()
210         script_lines[0] = '#!%s\n' % (sys.executable,)
211         for script_name in script_names:
212             tahoe_script = os.path.join("bin", script_name)
213             try:
214                 os.remove(tahoe_script)
215             except Exception:
216                 if os.path.exists(tahoe_script):
217                    raise
218             f = open(tahoe_script, "wb")
219             for line in script_lines:
220                 f.write(line)
221             f.close()
222
223         # chmod +x
224         unix_script = os.path.join("bin", "tahoe")
225         old_mode = stat.S_IMODE(os.stat(unix_script)[stat.ST_MODE])
226         new_mode = old_mode | (stat.S_IXUSR | stat.S_IRUSR |
227                                stat.S_IXGRP | stat.S_IRGRP |
228                                stat.S_IXOTH | stat.S_IROTH )
229         os.chmod(unix_script, new_mode)
230
231         old_tahoe_exe = os.path.join("bin", "tahoe.exe")
232         try:
233             os.remove(old_tahoe_exe)
234         except Exception:
235             if os.path.exists(old_tahoe_exe):
236                 raise
237
238
239 GIT_VERSION_BODY = '''
240 # This _version.py is generated from git metadata by the tahoe setup.py.
241
242 __pkgname__ = %(pkgname)r
243 real_version = %(version)r
244 full_version = %(full)r
245 branch = %(branch)r
246 verstr = %(normalized)r
247 __version__ = verstr
248 '''
249
250 def run_command(args, cwd=None, verbose=False):
251     try:
252         # remember shell=False, so use git.cmd on windows, not just git
253         p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd)
254     except EnvironmentError as e:  # if this gives a SyntaxError, note that Tahoe-LAFS requires Python 2.6+
255         if verbose:
256             print("unable to run %s" % args[0])
257             print(e)
258         return None
259     stdout = p.communicate()[0].strip()
260     if p.returncode != 0:
261         if verbose:
262             print("unable to run %s (error)" % args[0])
263         return None
264     return stdout
265
266
267 def versions_from_git(tag_prefix, verbose=False):
268     # this runs 'git' from the directory that contains this file. That either
269     # means someone ran a setup.py command (and this code is in
270     # versioneer.py, thus the containing directory is the root of the source
271     # tree), or someone ran a project-specific entry point (and this code is
272     # in _version.py, thus the containing directory is somewhere deeper in
273     # the source tree). This only gets called if the git-archive 'subst'
274     # variables were *not* expanded, and _version.py hasn't already been
275     # rewritten with a short version string, meaning we're inside a checked
276     # out source tree.
277
278     # versions_from_git (as copied from python-versioneer) returns strings
279     # like "1.9.0-25-gb73aba9-dirty", which means we're in a tree with
280     # uncommited changes (-dirty), the latest checkin is revision b73aba9,
281     # the most recent tag was 1.9.0, and b73aba9 has 25 commits that weren't
282     # in 1.9.0 . The narrow-minded NormalizedVersion parser that takes our
283     # output (meant to enable sorting of version strings) refuses most of
284     # that. Tahoe uses a function named suggest_normalized_version() that can
285     # handle "1.9.0.post25", so dumb down our output to match.
286
287     try:
288         source_dir = os.path.dirname(os.path.abspath(__file__))
289     except NameError:
290         # some py2exe/bbfreeze/non-CPython implementations don't do __file__
291         return {} # not always correct
292     GIT = "git"
293     if sys.platform == "win32":
294         GIT = "git.cmd"
295     stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"],
296                          cwd=source_dir)
297     if stdout is None:
298         return {}
299     if not stdout.startswith(tag_prefix):
300         if verbose:
301             print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix))
302         return {}
303     version = stdout[len(tag_prefix):]
304     pieces = version.split("-")
305     if len(pieces) == 1:
306         normalized_version = pieces[0]
307     else:
308         normalized_version = "%s.post%s" % (pieces[0], pieces[1])
309
310     stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=source_dir)
311     if stdout is None:
312         return {}
313     full = stdout.strip()
314     if version.endswith("-dirty"):
315         full += "-dirty"
316         normalized_version += ".dev0"
317
318     # Thanks to Jistanidiot at <http://stackoverflow.com/questions/6245570/get-current-branch-name>.
319     stdout = run_command([GIT, "rev-parse", "--abbrev-ref", "HEAD"], cwd=source_dir)
320     branch = (stdout or "unknown").strip()
321
322     return {"version": version, "normalized": normalized_version, "full": full, "branch": branch}
323
324 # setup.cfg has an [aliases] section which runs "update_version" before many
325 # commands (like "build" and "sdist") that need to know our package version
326 # ahead of time. If you add different commands (or if we forgot some), you
327 # may need to add it to setup.cfg and configure it to run update_version
328 # before your command.
329
330 class UpdateVersion(Command):
331     description = "update _version.py from revision-control metadata"
332     user_options = []
333
334     def initialize_options(self):
335         pass
336     def finalize_options(self):
337         pass
338     def run(self):
339         if os.path.isdir(os.path.join(basedir, ".git")):
340             verstr = self.try_from_git()
341         else:
342             print("no version-control data found, leaving _version.py alone")
343             return
344         if verstr:
345             self.distribution.metadata.version = verstr
346
347     def try_from_git(self):
348         versions = versions_from_git("allmydata-tahoe-", verbose=True)
349         if versions:
350             fn = 'src/allmydata/_version.py'
351             f = open(fn, "wb")
352             f.write(GIT_VERSION_BODY %
353                     { "pkgname": self.distribution.get_name(),
354                       "version": versions["version"],
355                       "normalized": versions["normalized"],
356                       "full": versions["full"],
357                       "branch": versions["branch"],
358                     })
359             f.close()
360             print("git-version: wrote '%s' into '%s'" % (versions["version"], fn))
361         return versions.get("normalized", None)
362
363
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/*
369     is included as well.
370     """
371
372     user_options = sdist.sdist.user_options + \
373         [('sumo', 's',
374           "create a 'sumo' sdist which includes the contents of tahoe-deps/*"),
375          ]
376     boolean_options = ['sumo']
377
378     def initialize_options(self):
379         sdist.sdist.initialize_options(self)
380         self.sumo = False
381
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().
389
390         if self.sumo:
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()
403             def get_fullname():
404                 return fullname + "-SUMO"
405             self.distribution.get_fullname = get_fullname
406
407         try:
408             old_mask = os.umask(int("022", 8))
409             return sdist.sdist.make_distribution(self)
410         finally:
411             os.umask(old_mask)
412
413
414 setup_args = {}
415 if version:
416     setup_args["version"] = version
417
418 setup(name=APPNAME,
419       description='secure, decentralized, fault-tolerant filesystem',
420       long_description=open('README.txt', '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.txt -- there is an alternative licence
425       cmdclass={"trial": Trial,
426                 "make_executable": MakeExecutable,
427                 "update_version": UpdateVersion,
428                 "sdist": MySdist,
429                 },
430       package_dir = {'':'src'},
431       packages=['allmydata',
432                 'allmydata.frontends',
433                 'allmydata.immutable',
434                 'allmydata.immutable.downloader',
435                 'allmydata.introducer',
436                 'allmydata.mutable',
437                 'allmydata.scripts',
438                 'allmydata.storage',
439                 'allmydata.test',
440                 'allmydata.util',
441                 'allmydata.web',
442                 'allmydata.windows',
443                 'buildtest'],
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",
450                                       "static/img/*.png",
451                                       "static/css/*.css",
452                                       ]
453                     },
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.
457       **setup_args
458       )