setup.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #!/usr/bin/env python
  2. """
  3. Sentry
  4. ======
  5. Sentry is a realtime event logging and aggregation platform. It specializes
  6. in monitoring errors and extracting all the information needed to do a proper
  7. post-mortem without any of the hassle of the standard user feedback loop.
  8. Sentry is a Server
  9. ------------------
  10. The Sentry package, at its core, is just a simple server and web UI. It will
  11. handle authentication clients (such as `Raven <https://github.com/getsentry/raven-python>`_)
  12. and all of the logic behind storage and aggregation.
  13. That said, Sentry is not limited to Python. The primary implementation is in
  14. Python, but it contains a full API for sending events from any language, in
  15. any application.
  16. :copyright: (c) 2011-2014 by the Sentry Team, see AUTHORS for more details.
  17. :license: BSD, see LICENSE for more details.
  18. """
  19. from __future__ import absolute_import
  20. import datetime
  21. import json
  22. import os.path
  23. from distutils import log
  24. from distutils.core import Command
  25. from setuptools.command.install import install
  26. from setuptools.command.develop import develop
  27. from setuptools.command.sdist import sdist
  28. from setuptools import setup, find_packages
  29. from subprocess import check_output
  30. # Hack to prevent stupid "TypeError: 'NoneType' object is not callable" error
  31. # in multiprocessing/util.py _exit_function when running `python
  32. # setup.py test` (see
  33. # http://www.eby-sarna.com/pipermail/peak/2010-May/003357.html)
  34. for m in ('multiprocessing', 'billiard'):
  35. try:
  36. __import__(m)
  37. except ImportError:
  38. pass
  39. ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__)))
  40. dev_requires = [
  41. 'flake8>=2.0,<2.1',
  42. ]
  43. tests_require = [
  44. 'blist', # used by cassandra
  45. 'casscache',
  46. 'cqlsh',
  47. 'elasticsearch',
  48. 'httpretty',
  49. 'pytest-cov>=1.4',
  50. 'pytest-timeout',
  51. 'python-coveralls',
  52. 'responses',
  53. 'riak',
  54. ]
  55. install_requires = [
  56. 'BeautifulSoup>=3.2.1,<3.3.0',
  57. 'celery>=3.1.8,<3.2.0',
  58. 'cssutils>=0.9.9,<0.10.0',
  59. 'Django>=1.6.0,<1.7',
  60. 'django-bitfield>=1.7.0,<1.8.0',
  61. 'django-crispy-forms>=1.4.0,<1.5.0',
  62. 'django-paging>=0.2.5,<0.3.0',
  63. 'django-jsonfield>=0.9.13,<0.9.14',
  64. 'django-picklefield>=0.3.0,<0.4.0',
  65. 'django-recaptcha>=1.0.0,<1.1.0',
  66. 'django-social-auth>=0.7.28,<0.8.0',
  67. 'django-statsd-mozilla>=0.3.14.0,<0.3.15.0',
  68. 'django-sudo>=1.1.3,<1.2.0',
  69. 'django-templatetag-sugar>=0.1.0',
  70. 'djangorestframework>=2.3.8,<2.4.0',
  71. 'email-reply-parser>=0.2.0,<0.3.0',
  72. 'enum34>=0.9.18,<0.10.0',
  73. 'exam>=0.5.1',
  74. 'gunicorn>=19.2.1,<20.0.0',
  75. 'ipaddr>=2.1.11,<2.2.0',
  76. 'logan>=0.7.1,<0.8.0',
  77. 'lxml>=3.4.1',
  78. 'mock>=0.8.0',
  79. 'nydus>=0.11.0,<0.12.0',
  80. 'markdown>=2.4.1,<2.5.0',
  81. 'petname>=1.7,<1.8',
  82. 'progressbar>=2.2,<2.4',
  83. 'pytest',
  84. 'pytest-django',
  85. 'python-dateutil>=2.0.0,<3.0.0',
  86. 'python-memcached>=1.53,<2.0.0',
  87. 'raven>=5.3.0',
  88. 'redis>=2.7.0,<2.11.0',
  89. 'requests[security]>=2.7.0,<2.8.0',
  90. 'simplejson>=3.1.0,<3.4.0',
  91. 'six>=1.6.0,<2.0.0',
  92. 'setproctitle>=1.1.7,<1.2.0',
  93. 'statsd>=3.1.0,<3.2.0',
  94. 'South==1.0.1',
  95. 'toronado>=0.0.4,<0.1.0',
  96. 'ua-parser>=0.3.5',
  97. 'urllib3>=1.7.1,<1.8.0',
  98. ]
  99. postgres_requires = [
  100. 'psycopg2>=2.5.0,<2.6.0',
  101. ]
  102. postgres_pypy_requires = [
  103. 'psycopg2cffi',
  104. ]
  105. mysql_requires = [
  106. 'MySQL-python>=1.2.0,<1.3.0',
  107. ]
  108. class DevelopWithBuildStatic(develop):
  109. def install_for_development(self):
  110. self.run_command('build_static')
  111. return develop.install_for_development(self)
  112. class SdistWithBuildStatic(sdist):
  113. def make_release_tree(self, *a, **kw):
  114. dist_path = self.distribution.get_fullname()
  115. sdist.make_release_tree(self, *a, **kw)
  116. self.reinitialize_command('build_static', work_path=dist_path)
  117. self.run_command('build_static')
  118. with open(os.path.join(dist_path, 'sentry-package.json'), 'w') as fp:
  119. json.dump({
  120. 'createdAt': datetime.datetime.utcnow().isoformat() + 'Z',
  121. }, fp)
  122. class BuildStatic(Command):
  123. user_options = [
  124. ('work-path=', 'w',
  125. "The working directory for source files. Defaults to ."),
  126. ]
  127. def initialize_options(self):
  128. self.work_path = None
  129. def finalize_options(self):
  130. if self.work_path is None:
  131. self.work_path = ROOT
  132. def run(self):
  133. work_path = self.work_path
  134. log.info("initializing git submodules")
  135. check_output(['git', 'submodule', 'init'], cwd=work_path)
  136. check_output(['git', 'submodule', 'update'], cwd=work_path)
  137. log.info("running [npm install --quiet]")
  138. check_output(['npm', 'install', '--quiet'], cwd=work_path)
  139. log.info("running [gulp dist]")
  140. check_output([os.path.join('node_modules', '.bin', 'gulp'), 'dist'],
  141. cwd=work_path)
  142. class SmartInstall(install):
  143. """
  144. Installs Sentry into the Python environment.
  145. If the package indicator is missing, this will also force a run of
  146. `build_static` which is required for JavaScript assets and other things.
  147. """
  148. def _needs_static(self):
  149. return not os.path.exists(os.path.join(ROOT, 'sentry-package.json'))
  150. def run(self):
  151. if self._needs_static():
  152. self.run_command('build_static')
  153. install.run(self)
  154. setup(
  155. name='sentry',
  156. version='7.8.0.dev0',
  157. author='David Cramer',
  158. author_email='dcramer@gmail.com',
  159. url='https://www.getsentry.com',
  160. description='A realtime logging and aggregation server.',
  161. long_description=open('README.rst').read(),
  162. package_dir={'': 'src'},
  163. packages=find_packages('src'),
  164. zip_safe=False,
  165. install_requires=install_requires,
  166. extras_require={
  167. 'tests': tests_require,
  168. 'dev': dev_requires,
  169. 'postgres': install_requires + postgres_requires,
  170. 'postgres_pypy': install_requires + postgres_pypy_requires,
  171. 'mysql': install_requires + mysql_requires,
  172. },
  173. cmdclass={
  174. 'build_static': BuildStatic,
  175. 'develop': DevelopWithBuildStatic,
  176. 'sdist': SdistWithBuildStatic,
  177. 'install': SmartInstall,
  178. },
  179. license='BSD',
  180. include_package_data=True,
  181. entry_points={
  182. 'console_scripts': [
  183. 'sentry = sentry.utils.runner:main',
  184. ],
  185. },
  186. classifiers=[
  187. 'Framework :: Django',
  188. 'Intended Audience :: Developers',
  189. 'Intended Audience :: System Administrators',
  190. 'Operating System :: OS Independent',
  191. 'Topic :: Software Development'
  192. ],
  193. )