Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 280 lines (227 sloc) 9.68 KB
#!/usr/bin/env python
# Authors:
# Steve Phillips --
# AJ v Bahnken --
# Requires virtualenv, virtualenvwrapper, and git
import os
import random
import re
import shutil
import string
import sys
from subprocess import Popen, call, STDOUT, PIPE
def which(program):
import os
def is_exe(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
fpath, fname = os.path.split(program)
if fpath:
if is_exe(program):
return program
for path in os.environ["PATH"].split(os.pathsep):
exe_file = os.path.join(path, program)
if is_exe(exe_file):
return exe_file
return None
import argparse
except ImportError:
print "argparse not installed. Please install with\n"
print " sudo pip install argparse\n"
print "then re-run this script."
# If user is in a virtualenv, tell them to get out first
if hasattr(sys, 'real_prefix'):
print "You're already in a virtualenv. Type\n"
print " deactivate\n"
print "to leave, then run this script again."
VIRTUALENV_WRAPPER_PATH = '/usr/local/bin/'
if not os.path.isfile(VIRTUALENV_WRAPPER_PATH):
output = call(cmd, shell=True)
if output:
print "We can not seem to find virtualenvwrapper\n"
print "Either install it through pip\n"
print " sudo pip install virtualenvwrapper\n"
print "or set $VIRTUALENV_WRAPPER_PATH to the location of\n"
print "virtualenvwrapper on your machine."
# We have what we need! Let's do this...
DPB_PATH = os.path.abspath(os.path.dirname(__file__)) + '/'
DJANGO_FILES_PATH = DPB_PATH + 'django-files/'
# These are the arguments for the builder. We can extend the
# arguments as we want to add more functionality
parser = argparse.ArgumentParser(description='''PTM Web Engineering presents
Django Project Builder''')
# Arg to declare the path to where the project will be made
parser.add_argument('--version', '-v', action='version',
version='Django Project Builder v0.1')
parser.add_argument('--path', action='store', dest='path',
help='''Specifies where the new Django project
should be made, including the project name at the
end (e.g. /home/username/code/project_name)''',
# Arg for using bootstrap rather than generic templates/media
parser.add_argument('--bootstrap', action='store_true', default=False,
help='''This will include Bootstrap as the template
and media base of the project.''', dest='bootstrap')
# Arg for using foundation rather than generic templates/media
parser.add_argument('--foundation', action='store_true', default=False,
help='''This will include Foundation 3 as the template
and media base of the project.''', dest='foundation')
# Simple ones
parser.add_argument('-q', '--quiet', action='store_true', default=False,
help='''Quiets all output except the finish message.''',
arguments = parser.parse_args()
def check_projectname():
if not'^[_a-zA-Z]\w*$', PROJECT_NAME):
message = 'Error: \'%s\' is not a valid project name. Please ' % PROJECT_NAME
if not'^[_a-zA-Z]', PROJECT_NAME):
message += ('make sure the name begins '
'with a letter or underscore.')
message += 'use only numbers, letters and underscores.'
def copy_files(folder_path, file_types, pathify):
"""Copies the contents of django_files and server_scripts, and
performs string interpolations (e.g., %(APP_NAME)s => 'myapp')"""
for filename in file_types:
# Grab *-needed filenames
f_read = open(folder_path + filename, 'r')
contents =
# Replace %(SECRET_KEY)s, etc with new value for new project
if filename.endswith('-needed'):
new_filename = filename.replace('-needed', '')
# Loop through list of locations new_filename should be placed
for dir in pathify[new_filename]:
# Path names include '%(PROJECT_NAME)s', etc
file_path = dir % replacement_values
f_write = open(PROJECT_PATH + file_path + new_filename, 'a')
new_contents = contents % replacement_values
def sh(cmd):
return Popen(cmd,shell=True,stdout=PIPE,stderr=PIPE).communicate()[0]
# Maps cleaned filenames to where each file should be copied relative
django_pathify = {
'.gitignore': [''],
'': ['%(PROJECT_NAME)s/', '%(APP_NAME)s/'],
'': ['%(APP_NAME)s/'],
'django.wsgi': ['apache/'],
'': ['%(APP_NAME)s/'],
'': [''],
'': ['%(APP_NAME)s/'],
'': ['%(APP_NAME)s/'],
'requirements.txt': [''],
'': ['%(PROJECT_NAME)s/'],
'': ['%(PROJECT_NAME)s/'],
'': ['%(APP_NAME)s/'],
'': ['%(PROJECT_NAME)s/'],
'': ['%(APP_NAME)s/'],
'': ['%(PROJECT_NAME)s/'],
# Trailing / may be included or excluded up to this point
PROJECT_PATH = arguments.path.rstrip('/') + '_site/'
PROJECT_NAME = PROJECT_PATH.split('/')[-2].split('_')[0] # Before the '_site/'
BASE_PATH = '/'.join(PROJECT_PATH.split('/')[:-2]) + '/'
# vewrapper = pbs.which('')
# vewrapper("")
SECRET_KEY = ''.join([ random.choice(string.printable[:94].replace("'", ""))
for _ in range(50) ])
PROJECT_PASSWORD = ''.join([ random.choice(string.printable[:62])
for _ in range(30) ])
# Defines key: value pairs so that
# '%(PROJECT_NAME)s' % replacement_values
# evaluates to the value of the `PROJECT_NAME` variable, such as
# 'my_project_name'
replacement_values = {
# Doing it this way so DPB can add 'extra_settings' on the fly.
needed_dirs = ['static', 'apache', '%(PROJECT_NAME)s', '%(APP_NAME)s']
# Make sure PROJECT_NAME follows Django's restrictions
if not arguments.quiet:
print "Creating directories..."
# Use 'git init' to create the PROJECT_PATH directory and turn it into
# a git repo
cmd = 'bash -c "git init %s"' % PROJECT_PATH
output = sh(cmd)
if not arguments.quiet:
print '\n', output, '\n'
# Create all other dirs (each a sub-(sub-?)directory) of PROJECT_PATH
for dir_name in needed_dirs:
os.mkdir(PROJECT_PATH + dir_name % replacement_values)
# Build list of all django-specific files to be copied into new project.
django_files = [x for x in os.listdir(DJANGO_FILES_PATH)
if x.endswith('-needed')]
if not arguments.quiet:
print "Creating django files..."
# Oddly-placed '%' in weird_files screws up our string interpolation,
# so copy these files verbatim
copy_files(DJANGO_FILES_PATH, django_files, django_pathify)
if not arguments.quiet:
print "Copying directories..."
# Add directory names here
generic_dirs = ['media', 'templates']
generic_dirs = [DPB_PATH + d for d in generic_dirs]
for dirname in generic_dirs:
# cp -r media-generic $PROJECT_PATH/media && cp -r templates-generic ...
new_dir = PROJECT_PATH + dirname.split('/')[-1]
if arguments.bootstrap:
shutil.copytree(dirname + '-bootstrap', new_dir)
shutil.copytree(dirname + '-foundation', new_dir)
shutil.copytree(dirname + '-generic', new_dir)
if not arguments.quiet:
print "Making virtualenv..."
cmd = 'bash -c "source %s &&' % VIRTUALENV_WRAPPER_PATH
cmd += ' mkvirtualenv %s --no-site-packages"' % PROJECT_NAME
output = sh(cmd)
if not arguments.quiet:
print '\n', output, '\n'
## The below part is made much faster with a small requirements.txt.
## We have the opitions to include more packages, which in turn
## will take long, but of course is needed. This allows for making
## projects which need only the basics, and ones that need a lot.
if not arguments.quiet:
print "Running 'pip install -r requirements.txt'. This could take a while...",
print "(don't press control-c!)"
# FIXME Shouldn't assume the location of
cmd = 'bash -c "source %s && workon' % VIRTUALENV_WRAPPER_PATH
cmd += ' %(PROJECT_NAME)s && cd %(PROJECT_PATH)s' % replacement_values
cmd += ' && pip install -r requirements.txt"'
output = sh(cmd)
if not arguments.quiet:
print '\n', output, '\n'
# virtualenv now exists
if not arguments.quiet:
print "Creating git repo..."
cmd = 'bash -c "cd %s &&' % PROJECT_PATH
cmd += ' git add . && git commit -m \'First commit\'"'
output = sh(cmd)
if not arguments.quiet:
print '\n', output, '\n'
print "\nDone! Now run\n"
print " cd %(PROJECT_PATH)s && workon %(PROJECT_NAME)s &&" % replacement_values,
print "python syncdb\n\nGet to work!"