PageRenderTime 66ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/funfactory/cmd.py

https://github.com/kumar303/funfactory
Python | 320 lines | 299 code | 1 blank | 20 comment | 0 complexity | c8041a05cfdfed2b53380e03fcdf1f52 MD5 | raw file
  1. """
  2. Installs a skeleton Django app based on Mozilla's Playdoh.
  3. 1. Clones the Playdoh repo
  4. 2. Renames the project module to your custom package name
  5. 3. Creates a virtualenv
  6. 4. Installs/compiles the requirements
  7. 5. Creates a local settings file
  8. Read more about it here: http://playdoh.readthedocs.org/
  9. """
  10. from contextlib import contextmanager
  11. import logging
  12. import optparse
  13. import os
  14. import random
  15. import re
  16. import shutil
  17. import subprocess
  18. import sys
  19. import textwrap
  20. allow_user_input = True
  21. verbose = True
  22. log = logging.getLogger(__name__)
  23. def clone_repo(pkg, dest, repo, repo_dest, branch):
  24. """Clone the Playdoh repo into a custom path."""
  25. git(['clone', '--recursive', '-b', branch, repo, repo_dest])
  26. def init_pkg(pkg, repo_dest):
  27. """
  28. Initializes a custom named package module.
  29. This works by replacing all instances of 'project' with a custom module
  30. name.
  31. """
  32. vars = {'pkg': pkg}
  33. with dir_path(repo_dest):
  34. patch("""\
  35. diff --git a/manage.py b/manage.py
  36. index 40ebb0a..cdfe363 100755
  37. --- a/manage.py
  38. +++ b/manage.py
  39. @@ -3,7 +3,7 @@ import os
  40. import sys
  41. # Edit this if necessary or override the variable in your environment.
  42. -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
  43. +os.environ.setdefault('DJANGO_SETTINGS_MODULE', '%(pkg)s.settings')
  44. try:
  45. # For local development in a virtualenv:
  46. diff --git a/project/settings/base.py b/project/settings/base.py
  47. index 312f280..c75e673 100644
  48. --- a/project/settings/base.py
  49. +++ b/project/settings/base.py
  50. @@ -7,7 +7,7 @@ from funfactory.settings_base import *
  51. # If you did not install Playdoh with the funfactory installer script
  52. # you may need to edit this value. See the docs about installing from a
  53. # clone.
  54. -PROJECT_MODULE = 'project'
  55. +PROJECT_MODULE = '%(pkg)s'
  56. # Bundles is a dictionary of two dictionaries, css and js, which list css files
  57. # and js files that can be bundled together by the minify app.
  58. diff --git a/setup.py b/setup.py
  59. index 58dbd93..9a38628 100644
  60. --- a/setup.py
  61. +++ b/setup.py
  62. @@ -3,7 +3,7 @@ import os
  63. from setuptools import setup, find_packages
  64. -setup(name='project',
  65. +setup(name='%(pkg)s',
  66. version='1.0',
  67. description='Django application.',
  68. long_description='',
  69. """ % vars)
  70. git(['mv', 'project', pkg])
  71. git(['commit', '-a', '-m', 'Renamed project module to %s' % pkg])
  72. def create_settings(pkg, repo_dest, db_user, db_name, db_password, db_host,
  73. db_port):
  74. """
  75. Creates a local settings file out of the distributed template.
  76. This also fills in database settings and generates a secret key, etc.
  77. """
  78. sk = ''.join([
  79. random.choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)')
  80. for i in range(50)])
  81. vars = {'pkg': pkg,
  82. 'db_user': db_user,
  83. 'db_name': db_name,
  84. 'db_password': db_password or '',
  85. 'db_host': db_host or '',
  86. 'db_port': db_port or '',
  87. 'secret_key': sk}
  88. with dir_path(repo_dest):
  89. shutil.copyfile('%s/settings/local.py-dist' % pkg,
  90. '%s/settings/local.py' % pkg)
  91. patch("""\
  92. --- a/%(pkg)s/settings/local.py
  93. +++ b/%(pkg)s/settings/local.py
  94. @@ -8,11 +8,11 @@
  95. DATABASES = {
  96. 'default': {
  97. 'ENGINE': 'django.db.backends.mysql',
  98. - 'NAME': 'playdoh_app',
  99. - 'USER': 'root',
  100. - 'PASSWORD': '',
  101. - 'HOST': '',
  102. - 'PORT': '',
  103. + 'NAME': '%(db_name)s',
  104. + 'USER': '%(db_user)s',
  105. + 'PASSWORD': '%(db_password)s',
  106. + 'HOST': '%(db_host)s',
  107. + 'PORT': '%(db_port)s',
  108. 'OPTIONS': {
  109. 'init_command': 'SET storage_engine=InnoDB',
  110. 'charset' : 'utf8',
  111. @@ -52,7 +52,7 @@ DEV = True
  112. # }
  113. # Make this unique, and don't share it with anybody. It cannot be blank.
  114. -SECRET_KEY = ''
  115. +SECRET_KEY = '%(secret_key)s'
  116. # Uncomment these to activate and customize Celery:
  117. # CELERY_ALWAYS_EAGER = False # required to activate celeryd
  118. """ % vars)
  119. def create_virtualenv(pkg, repo_dest, python):
  120. """Creates a virtualenv within which to install your new application."""
  121. workon_home = os.environ.get('WORKON_HOME')
  122. venv_cmd = find_executable('virtualenv')
  123. python_bin = find_executable(python)
  124. if not python_bin:
  125. raise EnvironmentError('%s is not installed or not '
  126. 'available on your $PATH' % python)
  127. if workon_home:
  128. # Can't use mkvirtualenv directly here because relies too much on
  129. # shell tricks. Simulate it:
  130. venv = os.path.join(workon_home, pkg)
  131. else:
  132. venv = os.path.join(repo_dest, '.virtualenv')
  133. if venv_cmd:
  134. if not verbose:
  135. log.info('Creating virtual environment in %r' % venv)
  136. args = ['--python', python_bin, venv]
  137. if not verbose:
  138. args.insert(0, '-q')
  139. subprocess.check_call([venv_cmd] + args)
  140. else:
  141. raise EnvironmentError('Could not locate the virtualenv. Install with '
  142. 'pip install virtualenv.')
  143. return venv
  144. def install_reqs(venv, repo_dest):
  145. """Installs all compiled requirements that can't be shipped in vendor."""
  146. with dir_path(repo_dest):
  147. args = ['-r', 'requirements/compiled.txt']
  148. if not verbose:
  149. args.insert(0, '-q')
  150. subprocess.check_call([os.path.join(venv, 'bin', 'pip'), 'install'] +
  151. args)
  152. def find_executable(name):
  153. """
  154. Finds the actual path to a named command.
  155. The first one on $PATH wins.
  156. """
  157. for pt in os.environ.get('PATH', '').split(':'):
  158. candidate = os.path.join(pt, name)
  159. if os.path.exists(candidate):
  160. return candidate
  161. def patch(hunk):
  162. args = ['-p1', '-r', '.']
  163. if not verbose:
  164. args.insert(0, '--quiet')
  165. ps = subprocess.Popen(['patch'] + args, stdin=subprocess.PIPE)
  166. ps.stdin.write(textwrap.dedent(hunk))
  167. ps.stdin.close()
  168. rs = ps.wait()
  169. if rs != 0:
  170. raise RuntimeError('patch %s returned non-zeo exit '
  171. 'status %s' % (file, rs))
  172. @contextmanager
  173. def dir_path(dir):
  174. """with dir_path(path) to change into a directory."""
  175. old_dir = os.getcwd()
  176. os.chdir(dir)
  177. yield
  178. os.chdir(old_dir)
  179. def git(cmd_args):
  180. args = ['git']
  181. cmd = cmd_args.pop(0)
  182. args.append(cmd)
  183. if not verbose:
  184. if cmd != 'mv': # doh
  185. args.append('--quiet')
  186. args.extend(cmd_args)
  187. if verbose:
  188. log.info(' '.join(args))
  189. subprocess.check_call(args)
  190. def resolve_opt(opt, prompt):
  191. if not opt:
  192. if not allow_user_input:
  193. raise ValueError('%s (value was not set, using --no-input)'
  194. % prompt)
  195. opt = raw_input(prompt)
  196. return opt
  197. def main():
  198. global allow_user_input, verbose
  199. ps = optparse.OptionParser(usage='%prog [options]\n' + __doc__)
  200. ps.add_option('-p', '--pkg', help='Name of your top level project package.')
  201. ps.add_option('-d', '--dest',
  202. help='Destination dir to put your new app. '
  203. 'Default: %default',
  204. default=os.getcwd())
  205. ps.add_option('-r', '--repo',
  206. help='Playdoh repository to clone. Default: %default',
  207. default='git://github.com/mozilla/playdoh.git')
  208. ps.add_option('-b', '--branch',
  209. help='Repository branch to clone. Default: %default',
  210. default='master')
  211. ps.add_option('--repo-dest',
  212. help='Clone repository into this directory. '
  213. 'Default: DEST/PKG')
  214. ps.add_option('--venv',
  215. help='Path to an existing virtualenv you want to use. '
  216. 'Otherwise, a new one will be created for you.')
  217. ps.add_option('-P', '--python',
  218. help='Python interpreter to use in your virtualenv. '
  219. 'Default: which %default',
  220. default='python')
  221. ps.add_option('--db-user',
  222. help='Database user of your new app. Default: %default',
  223. default='root')
  224. ps.add_option('--db-name',
  225. help='Database name for your new app. Default: %default',
  226. default='playdoh_app')
  227. ps.add_option('--db-password',
  228. help='Database user password. Default: %default',
  229. default=None)
  230. ps.add_option('--db-host',
  231. help='Database connection host. Default: %default',
  232. default=None)
  233. ps.add_option('--db-port',
  234. help='Database connection port. Default: %default',
  235. default=None)
  236. ps.add_option('--no-input', help='Never prompt for user input',
  237. action='store_true', default=False)
  238. ps.add_option('-q', '--quiet', help='Less output',
  239. action='store_true', default=False)
  240. (options, args) = ps.parse_args()
  241. logging.basicConfig(level=logging.INFO, format="%(message)s",
  242. stream=sys.stdout)
  243. allow_user_input = not options.no_input
  244. verbose = not options.quiet
  245. options.pkg = resolve_opt(options.pkg, 'Top level package name: ')
  246. if not re.match('[a-zA-Z0-9_]+', options.pkg):
  247. ps.error('Package name %r can only contain letters, numbers, and '
  248. 'underscores' % options.pkg)
  249. if not find_executable('mysql_config'):
  250. ps.error('Cannot find mysql_config. Please install MySQL!')
  251. if not options.repo_dest:
  252. options.repo_dest = os.path.abspath(os.path.join(options.dest,
  253. options.pkg))
  254. clone_repo(options.pkg, options.dest, options.repo, options.repo_dest,
  255. options.branch)
  256. if options.venv:
  257. venv = options.venv
  258. elif os.environ.get('VIRTUAL_ENV'):
  259. venv = os.environ['VIRTUAL_ENV']
  260. log.info('Using existing virtualenv in %s' % venv)
  261. else:
  262. venv = create_virtualenv(options.pkg, options.repo_dest, options.python)
  263. install_reqs(venv, options.repo_dest)
  264. init_pkg(options.pkg, options.repo_dest)
  265. create_settings(options.pkg, options.repo_dest, options.db_user,
  266. options.db_name, options.db_password, options.db_host,
  267. options.db_port)
  268. if verbose:
  269. log.info('')
  270. log.info('Aww yeah. Just installed you some Playdoh.')
  271. log.info('')
  272. log.info('cd %s' % options.repo_dest)
  273. if os.environ.get('WORKON_HOME'):
  274. log.info('workon %s' % options.pkg)
  275. else:
  276. log.info('source %s/bin/activate'
  277. % venv.replace(options.repo_dest, '.'))
  278. log.info('python manage.py runserver')
  279. log.info('')
  280. if __name__ == '__main__':
  281. main()