2 #_____________________________________________________________________________
4 # This file is part of BridgeDB, a Tor bridge distribution system.
6 # :authors: Isis Lovecruft 0xA3ADB67A2CDB8B35 <isis@torproject.org>
7 # Aaron Gibson 0x2C4B239DD876C9F6 <aagbsn@torproject.org>
8 # Nick Mathewson 0x21194EBB165733EA <nickm@torproject.org>
9 # please also see AUTHORS file
10 # :copyright: (c) 2007-2013, The Tor Project, Inc.
11 # (c) 2007-2013, all entities within the AUTHORS file
12 # :license: see LICENSE for licensing information
13 #_____________________________________________________________________________
15 from __future__
import print_function
23 # Fix circular dependency with setup.py install
25 from babel
.messages
.frontend
import compile_catalog
, extract_messages
26 from babel
.messages
.frontend
import init_catalog
, update_catalog
28 compile_catalog
= extract_messages
= init_catalog
= update_catalog
= None
35 # Repo directory that contains translations; this directory should contain
36 # both uncompiled translations (.po files) as well as compiled ones (.mo
37 # files). We only want to install the .mo files.
38 repo_i18n
= os
.path
.join(pkgpath
, 'i18n')
40 # The list of country codes for supported languages will be stored as a list
41 # variable, ``_supported``, in this file, so that the bridgedb packages
42 # __init__.py can access it:
43 repo_langs
= os
.path
.join(pkgpath
, '_langs.py')
45 # The directory containing template files and other resources to serve on the
47 repo_templates
= os
.path
.join(pkgpath
, 'distributors', 'https', 'templates')
49 # The directories to install non-sourcecode resources into should always be
50 # given as relative paths, in order to force distutils to install relative to
51 # the rest of the codebase.
53 # Directory to installed compiled translations (.mo files) into:
54 install_i18n
= os
.path
.join('bridgedb', 'i18n')
56 # Directory to install docs, license, and other text resources into:
57 install_docs
= os
.path
.join('share', 'doc', 'bridgedb')
61 """Get our cmdclass dictionary for use in setuptool.setup().
63 This must be done outside the call to setuptools.setup() because we need
64 to add our own classes to the cmdclass dictionary, and then update that
65 dictionary with the one returned from versioneer.get_cmdclass().
67 cmdclass
= {'test': Trial
,
68 'compile_catalog': compile_catalog
,
69 'extract_messages': extract_messages
,
70 'init_catalog': init_catalog
,
71 'update_catalog': update_catalog
}
72 cmdclass
.update(versioneer
.get_cmdclass())
75 def get_requirements():
76 """Extract the list of requirements from our requirements.txt.
79 :returns: Two lists, the first is a list of requirements in the form of
80 pkgname==version. The second is a list of URIs or VCS checkout strings
81 which specify the dependency links for obtaining a copy of the
84 requirements_file
= os
.path
.join(os
.getcwd(), 'requirements.txt')
88 with
open(requirements_file
) as reqfile
:
89 for line
in reqfile
.readlines():
91 if line
.startswith('#'):
93 if line
.startswith(('git+', 'hg+', 'svn+')):
94 line
= line
[line
.index('+') + 1:]
96 ('https://', 'git://', 'hg://', 'svn://')):
99 requirements
.append(line
)
101 except (IOError, OSError) as error
:
104 return requirements
, links
106 def get_supported_langs():
107 """Get the paths for all compiled translation files.
109 The two-letter country code of each language which is going to be
110 installed will be added to a list, and this list will be written to
111 :attr:`repo_langs`, so that bridgedb/__init__.py can store a
112 package-level attribute ``bridgedb.__langs__``, which will be a list of
113 any languages which were installed.
115 Then, the paths of the compiled translations files are added to
116 :ivar:`data_files`. These should be included in the ``data_files``
117 parameter in :func:`~setuptools.setup` in order for setuptools to be able
118 to tell the underlying distutils ``install_data`` command to include these
121 See http://docs.python.org/2/distutils/setupscript.html#installing-additional-files
122 for more information.
124 :ivar list supported: A list of two-letter country codes, one for each
125 language we currently provide translations support for.
126 :ivar list lang_dirs: The directories (relative or absolute) to install
127 the compiled translation file to.
128 :ivar list lang_files: The paths to compiled translations files, relative
129 to this setup.py script.
131 :returns: Two lists, ``lang_dirs`` and ``lang_files``.
137 for lang
in os
.listdir(repo_i18n
):
138 if lang
.endswith('templates'):
140 supported
.append(lang
)
141 lang_dirs
.append(os
.path
.join(install_i18n
, lang
))
142 lang_files
.append(os
.path
.join(repo_i18n
, lang
,
143 'LC_MESSAGES', 'bridgedb.mo'))
146 # Write our list of supported languages to 'bridgedb/_langs.py':
148 with
open(repo_langs
, 'r') as langsfile
:
149 for line
in langsfile
.readlines():
150 if line
.startswith('supported'):
151 # Change the 'supported' list() into a set():
152 line
= "supported = set(%s)\n" % supported
153 new_langs_lines
.append(line
)
154 with
open(repo_langs
, 'w') as newlangsfile
:
155 for line
in new_langs_lines
:
156 newlangsfile
.write(line
)
158 return lang_dirs
, lang_files
160 def get_template_files():
161 """Return the paths to any web resource files to include in the package.
164 :returns: Any files in :attr:`repo_templates` which match one of the glob
165 patterns in :ivar:`include_patterns`.
167 include_patterns
= ['*.html',
173 'assets/font/*.woff',
178 'assets/images/*.svg',
179 'assets/images/*.ico']
182 for include_pattern
in include_patterns
:
183 pattern
= os
.path
.join(repo_templates
, include_pattern
)
184 matches
= glob(pattern
)
185 template_files
.extend(matches
)
187 return template_files
189 def get_data_files(filesonly
=False):
190 """Return any hard-coded data_files which should be distributed.
192 This is necessary so that both the distutils-derived :class:`installData`
193 class and the setuptools ``data_files`` parameter include the same files.
194 Call this function with ``filesonly=True`` to get a list of files suitable
195 for giving to the ``package_data`` parameter in ``setuptools.setup()``.
196 Or, call it with ``filesonly=False`` (the default) to get a list which is
197 suitable for using as ``distutils.command.install_data.data_files``.
199 :param bool filesonly: If true, only return the locations of the files to
200 install, not the directories to install them into.
202 :returns: If ``filesonly``, returns a list of file paths. Otherwise,
203 returns a list of 2-tuples containing: one, the directory to install
204 to, and two, the files to install to that directory.
207 doc_files
= ['README', 'TODO', 'LICENSE', 'requirements.txt']
208 lang_dirs
, lang_files
= get_supported_langs()
209 template_files
= get_template_files()
212 data_files
.extend(doc_files
)
213 for lst
in lang_files
, template_files
:
215 if filename
.startswith(pkgpath
):
216 # The +1 gets rid of the '/' at the beginning:
217 filename
= filename
[len(pkgpath
) + 1:]
218 data_files
.append(filename
)
220 data_files
.append((install_docs
, doc_files
))
221 for ldir
, lfile
in zip(lang_dirs
, lang_files
):
222 data_files
.append((ldir
, [lfile
,]))
224 #[sys.stdout.write("Added data_file '%s'\n" % x) for x in data_files]
229 class Trial(setuptools
.Command
):
230 """Twisted Trial setuptools command.
232 Based on the setuptools Trial command in Zooko's Tahoe-LAFS, as well as
233 https://github.com/simplegeo/setuptools-trial/ (which is also based on the
236 Pieces of the original implementation of this 'test' command (that is, for
237 the original pyunit-based BridgeDB tests which, a long time ago, in a
238 galaxy far far away, lived in bridgedb.Tests) were based on setup.py from
239 Nick Mathewson's mixminion, which was based on the setup.py from Zooko's
240 pyutil package, which was in turn based on
241 http://mail.python.org/pipermail/distutils-sig/2002-January/002714.html.
243 Crusty, old-ass Python, like hella wut.
245 description
= "Run Twisted Trial-based tests."
247 ('debug', 'b', ("Run tests in a debugger. If that debugger is pdb, will "
248 "load '.pdbrc' from current directory if it exists.")),
249 ('debug-stacktraces', 'B', "Report Deferred creation and callback stack traces"),
250 ('debugger=', None, ("The fully qualified name of a debugger to use if "
251 "--debug is passed (default: pdb)")),
252 ('disablegc', None, "Disable the garbage collector"),
253 ('force-gc', None, "Have Trial run gc.collect() before and after each test case"),
254 ('jobs=', 'j', "Number of local workers to run, a strictly positive integer"),
255 ('profile', None, "Run tests under the Python profiler"),
256 ('random=', 'Z', "Run tests in random order using the specified seed"),
257 ('reactor=', 'r', "Which reactor to use"),
258 ('reporter=', None, "Customize Trial's output with a reporter plugin"),
259 ('rterrors', 'e', "Realtime errors: print out tracebacks as soon as they occur"),
260 ('spew', None, "Print an insanely verbose log of everything that happens"),
261 ('testmodule=', None, "Filename to grep for test cases (-*- test-case-name)"),
262 ('tbformat=', None, ("Specify the format to display tracebacks with. Valid "
263 "formats are 'plain', 'emacs', and 'cgitb' which uses "
264 "the nicely verbose stdlib cgitb.text function")),
265 ('unclean-warnings', None, "Turn dirty reactor errors into warnings"),
266 ('until-failure', 'u', "Repeat a test (specified by -s) until it fails."),
267 ('without-module=', None, ("Fake the lack of the specified modules, separated "
270 boolean_options
= ['debug', 'debug-stacktraces', 'disablegc', 'force-gc',
271 'profile', 'rterrors', 'spew', 'unclean-warnings',
274 def initialize_options(self
):
276 self
.debug_stacktraces
= None
278 self
.disablegc
= None
287 self
.testmodule
= None
289 self
.unclean_warnings
= None
290 self
.until_failure
= None
291 self
.without_module
= None
293 def finalize_options(self
):
294 build
= self
.get_finalized_command('build')
295 self
.build_purelib
= build
.build_purelib
296 self
.build_platlib
= build
.build_platlib
299 self
.run_command('build')
300 old_path
= sys
.path
[:]
301 sys
.path
[0:0] = [self
.build_purelib
, self
.build_platlib
]
305 result
= self
.run_tests()
308 raise SystemExit(result
)
311 # We do the import from Twisted inside the function instead of the top
312 # of the file because since Twisted is a setup_requires, we can't
313 # assume that Twisted will be installed on the user's system prior, so
314 # if we don't do the import here, then importing from this plugin will
316 from twisted
.scripts
import trial
318 if not self
.testmodule
:
319 self
.testmodule
= "bridgedb.test"
321 # Handle parsing the trial options passed through the setuptools
324 for opt
in self
.boolean_options
:
325 if getattr(self
, opt
.replace('-', '_'), None):
326 cmd_options
.append('--%s' % opt
)
328 for opt
in ('debugger', 'jobs', 'random', 'reactor', 'reporter',
329 'testmodule', 'tbformat', 'without-module'):
330 value
= getattr(self
, opt
.replace('-', '_'), None)
331 if value
is not None:
332 cmd_options
.extend(['--%s' % opt
, value
])
334 config
= trial
.Options()
335 config
.parseOptions(cmd_options
)
336 config
['tests'] = [self
.testmodule
,]
338 trial
._initialDebugSetup
(config
)
339 trialRunner
= trial
._makeRunner
(config
)
340 suite
= trial
._getSuite
(config
)
343 if self
.until_failure
:
344 test_result
= trialRunner
.runUntilFailure(suite
)
346 test_result
= trialRunner
.run(suite
)
348 if test_result
.wasSuccessful():
353 # If there is an environment variable BRIDGEDB_INSTALL_DEPENDENCIES=0, it will
354 # disable checking for, fetching, and installing BridgeDB's dependencies with
357 # Setting BRIDGEDB_INSTALL_DEPENDENCIES=0 is *highly* recommended, because
358 # easy_install is a security nightmare. Automatically installing dependencies
359 # is enabled by default, however, because this is how all Python packages are
361 if bool(int(os
.environ
.get("BRIDGEDB_INSTALL_DEPENDENCIES", 1))):
362 requires
, deplinks
= get_requirements()
364 requires
, deplinks
= [], []
369 version
=versioneer
.get_version(),
370 description
='Backend systems for distribution of Tor bridge relays',
371 author
='Nick Mathewson',
372 author_email
='nickm at torproject dot org',
373 maintainer
='Philipp Winter',
374 maintainer_email
='phw@torproject.org',
375 url
='https://www.torproject.org',
376 download_url
='https://gitweb.torproject.org/bridgedb.git',
377 package_dir
={'bridgedb': 'bridgedb'},
378 packages
=['bridgedb',
379 'bridgedb.distributors',
380 'bridgedb.distributors.common',
381 'bridgedb.distributors.email',
382 'bridgedb.distributors.https',
383 'bridgedb.distributors.moat',
387 scripts
=['scripts/bridgedb',
388 'scripts/get-tor-exits'],
389 extras_require
={'test': ["sure==1.2.2",
391 "cryptography==1.9"]},
393 cmdclass
=get_cmdclass(),
394 include_package_data
=True,
395 install_requires
=requires
,
396 dependency_links
=deplinks
,
397 package_data
={'bridgedb': get_data_files(filesonly
=True)},
398 exclude_package_data
={'bridgedb': ['*.po', '*.pot']},
401 ('**.py', 'python', None),
402 ('distributors/https/templates/**.html', 'mako', None),