# Libs import sys import os from subprocess import call, Popen, PIPE from shutil import copytree # Config APP_DIRECTORY = './app' GIT_REPOSITORY = 'git@bitbucket.org:fmartingr/minecraftcodex.git' GIT_DOWNLOAD_DIR = './src' GIT_APP_PATH = 'minecraftcodex' GIT_PATH_THIS = '%s/config/production/deploy.py' % GIT_DOWNLOAD_DIR VIRTUALENV_PATH = './virtualenv' CHECK_SCRIPT_UPDATE = True PYTHON = { 'py': 'python2', 'pip': 'pip2', 'virtualenv': 'virtualenv2' } PIP_REQUIREMENTS_FILES = [ '%s/config/production/requirements.pip' % GIT_DOWNLOAD_DIR ] CONFIG_FILES = [ ( '%s/config/production/local_settings.py' % GIT_DOWNLOAD_DIR, '%s/herobrine/local_settings.py' % APP_DIRECTORY ), ( '%s/config/production/nginx.conf' % GIT_DOWNLOAD_DIR, './conf/nginx.conf' ), ( '%s/config/production/app.supervisor.conf' % GIT_DOWNLOAD_DIR, './conf/app.supervisor.conf' ), ( '%s/config/server/server.sh' % GIT_DOWNLOAD_DIR, './server.sh' ), ] FIXTURES = [ #'%s/config/production/initial_data.json' % GIT_DOWNLOAD_DIR ] REQUIREMENTS = [ 'git', 'coffee', 'lessc', 'uglifyjs' ] # Paths relatives to APP DIR PREPROCESSORS = { 'coffee': { 'items': [ ('blog/static/coffee/load_redactor.coffee', 'blog/static/js/load_redactor.big.js'), ], 'params': '' }, 'less': { 'items': [ ('database/static/lib/bootstrap/less/bootstrap.less', 'database/static/lib/bootstrap.css'), ('database/static/lib/bootstrap/less/responsive.less', 'database/static/lib/responsive.css'), ('database/static/less/style.less', 'database/static/css/style.css'), ], 'params': '-s -x' }, 'uglify': { 'items': [ ('blog/static/js/load_redactor.big.js', 'blog/static/js/load_redactor.js'), ], 'params': '-c warnings=false' } } ENVIRONMENT_VARIABLES = [ 'DATABASE_HOST', 'DATABASE_USER', 'DATABASE_PASS', 'DATABASE_PORT', 'DATABASE_NAME' ] SERVER_PORT = 8001 RUNSERVER_PARAMS = "0.0.0.0:%d" % SERVER_PORT CONTINUE = True # Functions class Colors: END = '\033[0m' def __init__(self, c='ter,'): if c == 'custom': self.custom() else: self.term() def custom(self): self.WHITE = '\033[89m' self.BLACK = '\033[90m' self.RED = '\033[91m' self.GREEN = '\033[92m' self.YELLOW = '\033[93m' self.BLUE = '\033[94m' self.PURPLE = '\033[95m' self.CYAN = '\033[96m' def term(self): self.WHITE = '\033[29m' self.BLACK = '\033[30m' self.RED = '\033[31m' self.GREEN = '\033[32m' self.YELLOW = '\033[33m' self.BLUE = '\033[34m' self.PURPLE = '\033[35m' self.CYAN = '\033[36m' colors = Colors('custom') def echo(string, end='\r\n', color=None): if color: sys.stdout.write("%s%s%s" % ( color, string, colors.END )) else: sys.stdout.write(string) if end: sys.stdout.write("\n") sys.stdout.flush() # Shortcurts def check_status(status=None, words=['done', 'failed']): if status is not None: if status == 0: echo(words[0], color=colors.GREEN) else: echo(words[1], color=colors.RED) pass #exit(-1) def exists(path): return os.path.exists(path) def title(string): print("") echo("[==] %s" % string, color=colors.PURPLE) def info(string): echo("[ i] %s" % string, color=colors.BLUE) def error(string): echo("[ E] %s" % string, color=colors.RED) def success(string): echo("[OK] %s" % string, color=colors.GREEN) def sub(string, end=''): echo(" %s " % string, end=end) # Checking if there's an active virtualenv if 'VIRTUAL_ENV' in os.environ: error('Active virtualenv detected. Deactivate it first.') exit(-2) os.system('clear') info("Running from %s" % os.getcwd()) # =============== CHECK REQUIREMENTS =============== title('Checking requirements') for req in REQUIREMENTS: sub('%s:' % req) status = call(["which", req], stdout=open(os.devnull, 'wb')) check_status(status, words=['present', 'not present']) if status != 0: CONTINUE = False # ========== CHECK ENVIRONMENT VARIABLES ========== title('Checking environment variables') for env in ENVIRONMENT_VARIABLES: sub('%s:' % env) if env in os.environ: status = 0 else: CONTINUE = False status = -1 check_status(status, words=['present', 'not present']) # Prequisites check if not CONTINUE: print("") error('Prequisites not met. Abort.') #error('You should CTRL+C now, errors may occur!') exit(-1) # ================== GIT DOWNLOAD ================== title('Getting last source code') if not exists(GIT_DOWNLOAD_DIR): os.mkdir(GIT_DOWNLOAD_DIR) sub('git clone:') status = call(['git', 'clone', GIT_REPOSITORY, GIT_DOWNLOAD_DIR], stdout=open(os.devnull, 'wb'), stderr=open(os.devnull, 'wb')) else: sub('git pull:') status = call(['git', 'pull'], cwd=GIT_DOWNLOAD_DIR, stdout=open(os.devnull, 'wb'), stderr=open(os.devnull, 'wb')) check_status(status) sub('Storing current version:') status = call('cd %s && git describe' % GIT_DOWNLOAD_DIR, stdout=open('./conf/app_version', 'wb'), stderr=open(os.devnull, 'wb'), shell=True) check_status(status) # =========== CHECK SCRIPT UPDATE ================== title('Checking if deploy script is updated on repository') actual_size = os.stat('./deploy.py').st_size repository_size = os.stat(GIT_PATH_THIS).st_size if repository_size != actual_size and CHECK_SCRIPT_UPDATE: sub('Script is updated.', end='\r\n') sub('Deleting old script:') status = call(['rm', './deploy.py'], stdout=open(os.devnull, 'wb')) check_status(status) sub('Installing new version:') status = call(['cp', GIT_PATH_THIS, './deploy.py'], stdout=open(os.devnull, 'wb')) check_status(status) info('Restarting execution!') os.system('%s ./deploy.py' % PYTHON['py']) exit(0) else: sub('Script is up-to-date.', end='\r\n') # =========== VIRTUALENV ========================= title('Checking and updating virtualenv') if not exists(VIRTUALENV_PATH): sub('Creating virtualenv:') status = call([PYTHON['virtualenv'], '-q', '--distribute', VIRTUALENV_PATH], stdout=open(os.devnull, 'wb')) check_status(status) else: sub('Virtualenv exists.', end='\r\n') title('Updating requirements') for requirements in PIP_REQUIREMENTS_FILES: sub('From %s:' % requirements) if exists(requirements): if os.stat(requirements).st_size > 0: status = call( 'source %s/bin/activate && pip install -r %s' % ( VIRTUALENV_PATH, requirements, ), stdout=open(os.devnull, 'wb'), shell=True, executable='/bin/bash' ) check_status(status) else: echo('empty', color=colors.YELLOW) else: echo('not exist', color=colors.RED) # ================== APP INSTALL ================== title('Installing the app') sub('Removing old data (if any):') if exists(APP_DIRECTORY): status = call(['rm', '-rf', APP_DIRECTORY], stdout=open(os.devnull, 'wb')) check_status(status) #call(['mkdir', APP_DIRECTORY]) sub('Copy source to application dir:') git_path = "%s/%s" % (GIT_DOWNLOAD_DIR, GIT_APP_PATH) app_path = "%s" % (APP_DIRECTORY) try: copytree(git_path, app_path) echo('done', color=colors.GREEN) except Exception as error: echo(error, color=colors.RED) #status = call(['cp', '-r', git_path, app_path], # stdout=open(os.devnull, 'wb')) #check_status(status) title('Installing config files') for from_file, to_file in CONFIG_FILES: sub('%s:' % os.path.basename(from_file)) if exists(from_file): if os.stat(from_file).st_size > 0: status = call(['cp', from_file, to_file], stdout=open(os.devnull, 'wb')) check_status(status) else: echo('empty', color=colors.YELLOW) else: echo('not exists', color=colors.RED) # ============ DATABASE MIGRATIONS ============== title('Database migrations') # Syncdb sub('django syncdb:') status = call( 'source %s/bin/activate && python %s/manage.py syncdb --noinput' % ( VIRTUALENV_PATH, APP_DIRECTORY ), stdout=open(os.devnull, 'wb'), shell=True, executable='/bin/bash' ) check_status(status) if FIXTURES: # Loading fixtures for fixture in FIXTURES: sub('[fixture] %s:' % fixture) status = call( 'source %s/bin/activate && python %s/manage.py loaddata %s' % ( VIRTUALENV_PATH, APP_DIRECTORY, fixture ), stdout=open(os.devnull, 'wb'), shell=True, executable='/bin/bash' ) check_status(status, words=['installed', 'not installed']) # South migrate sub('south migrate:') status = call( 'source %s/bin/activate && python %s/manage.py migrate' % ( VIRTUALENV_PATH, APP_DIRECTORY ), stdout=open(os.devnull, 'wb'), shell=True, executable='/bin/bash' ) check_status(status) # ================= COMPILERS =================== if PREPROCESSORS['coffee']['items']: title('Coffeescript compiling') for coffee in PREPROCESSORS['coffee']['items']: sub("%s:" % coffee[0]) path = "%s/%s" % (APP_DIRECTORY, coffee[0]) path_to = "%s/%s" % (APP_DIRECTORY, coffee[1]) params = ['coffee', '-p', path, '>', path_to] status = call(" ".join(params), stdout=open(os.devnull, 'wb'), shell=True) check_status(status, words=[os.path.basename(path_to), 'failed']) if PREPROCESSORS['uglify']['items']: title('Javascript compressing') sub('Original files are removed.', end='\r\n') for javascript in PREPROCESSORS['uglify']['items']: sub("+ %s:" % javascript[0]) path = "%s/%s" % (APP_DIRECTORY, javascript[0]) path_to = "%s/%s" % (APP_DIRECTORY, javascript[1]) params = ['uglifyjs', path, PREPROCESSORS['uglify']['params'], '>', path_to] status = call(" ".join(params), stdout=open(os.devnull, 'wb'), stderr=open(os.devnull, 'wb'), shell=True) check_status(status, words=[os.path.basename(path_to), 'failed']) sub('- Deleting %s:' % path) status = call(['rm', path], stdout=open(os.devnull, 'wb'), stderr=open(os.devnull, 'wb')) check_status(status) if PREPROCESSORS['less']['items']: title('LESS compiling and CSS compressing') for item in PREPROCESSORS['less']['items']: sub("%s:" % item[0]) path = "%s/%s" % (APP_DIRECTORY, item[0]) path_to = "%s/%s" % (APP_DIRECTORY, item[1]) params = ['lessc', PREPROCESSORS['less']['params'], path, '>', path_to] status = call(" ".join(params), stdout=open(os.devnull, 'wb'), shell=True) check_status(status, words=[os.path.basename(path_to), 'failed']) title('Collecting all staticfiles') sub('manage.py ollectstatic:') status = call( 'source %s/bin/activate && python %s/manage.py collectstatic --noinput' % ( VIRTUALENV_PATH, APP_DIRECTORY ), stdout=open(os.devnull, 'wb'), shell=True, executable='/bin/bash' ) check_status(status) # ================ SERVER ======================= title('Server') #sub('Killing all gunicorn_django instances') #status = call(['killall', 'gunicorn_django'], # stdout=open(os.devnull, 'wb'), # stderr=open(os.devnull, 'wb')) #check_status(status) sub('Restarting with supervisor') status = call(['sudo', 'supervisorctl', 'restart', 'gunicorn'], stdout=open(os.devnull, 'wb'), stderr=open(os.devnull, 'wb')) check_status(status) print("") success('Finished!')