Edit file File name : stage.py Content :import os import re import sys import shutil import fileinput from cement import App, Controller, ex from cement import shell from dhwp.core.git import Git from dhwp.core.wordpress import Wordpress class Stage(Controller): class Meta: label = 'stage' description = 'staging commands' stacked_on = 'base' stacked_type = 'nested' arguments = [ (['-p', '--path'], {'help': 'path to live wordpress install', 'action': 'store', 'dest': 'path', }), (['-d', '--destination'], {'help': 'path to staging', 'action': 'store', 'dest': 'destination', }), ] @ex( help='create a new staging environment', arguments=[ (['--url'], {'help': 'staging site url', 'action': 'store', 'dest': 'url'}), (['--dbname'], {'help': 'staging database name', 'action': 'store', 'dest': 'dbname'}), ] ) def create(self): if not self.app.pargs.destination: self.app.log.fatal("destination is required") sys.exit(1) destination = self.app.pargs.destination live_wp = Wordpress(self.app.pargs.path) live_url = live_wp.site_url() live_git = Git(self.app.pargs.path) self.delete() if not os.path.isdir(destination): os.makedirs(destination, 0o755) if os.listdir(destination): self.app.log.fatal("destination is not empty") sys.exit(1) self.app.log.info("Initalize live repository at %s" % self.app.pargs.path) live_git.cmd('init') self.app.log.info("Commiting all changes in %s" % self.app.pargs.path) live_git.commit('staging create', exclude_media=True, exclude_live_archives=True) self.app.log.info("Creating new git worktree at %s" % destination) live_git.cmd('worktree', 'add -b staging ' + destination + ' master -f') self.app.log.info("Copying over wp-config from %s to %s" % (self.app.pargs.path, self.app.pargs.destination)) r = re.compile(r"https?://(www\.)?") domain = r.sub('', live_url).strip().strip('/') with open(os.path.join(self.app.pargs.path, 'wp-config.php'), 'r') as conf, \ open(os.path.join(self.app.pargs.destination, 'wp-config.php'), 'w') as stage_conf: for line in conf: wp_home = all(w in line for w in ('WP_HOME', domain)) wp_siteurl = all(w in line for w in ('WP_SITEURL', domain)) if wp_home or wp_siteurl: self.app.log.info( "Generating file %s: removed line %s" % ( os.path.join(self.app.pargs.destination, 'wp-config.php'), line)) else: stage_conf.write(line) stage_wp = Wordpress(destination) stage_r = re.compile(r"^www\.") stage_domain = stage_r.sub('', self.app.pargs.url) stage_url = 'https://' + stage_domain stage_db_file = destination + '/db.sql' self.app.log.info("Creating Live backup") live_wp.db_export(stage_db_file) self.app.log.info("Importing live DB backup to stage") stage_wp.cli('config set DB_NAME ' + self.app.pargs.dbname) stage_wp.db_import(stage_db_file) os.unlink(stage_db_file) self.app.log.info("Setting Jetpack to staging mode") stage_wp.cli('config set JETPACK_STAGING_MODE true --add --type=constant --raw') self.app.log.info("Setting WordPress to staging mode") stage_wp.cli('config set WP_ENVIRONMENT_TYPE staging --add --type=constant') self.app.log.info("Setting Redis plugin to use own separate DB") stage_wp.cli('config set WP_REDIS_DATABASE 1 --add --type=constant --raw') self.app.log.info("Setting WordPress to not auto-update") stage_wp.cli('config set AUTOMATIC_UPDATER_DISABLED true --add --type=constant') self.app.log.info("Renaming WP site from %s to %s" % (live_url, stage_url)) stage_wp.rename(live_url, stage_url) self.app.log.info("Regenerating the .htaccess file") stage_wp.cli('rewrite flush --hard') @ex( help='commit changes to environment', arguments=[ (['--all'], {'help': 'commit db and files', 'action': 'store_true', 'dest': 'all_changes', }), (['--files'], {'help': 'commit files only', 'action': 'store_true', 'dest': 'file_changes', }), (['--db'], {'help': 'commit database changes', 'action': 'store_true', 'dest': 'db_changes', }), ] ) def commit(self): stage_wp = Wordpress(self.app.pargs.destination) live_wp = Wordpress(self.app.pargs.path) live_git = Git(self.app.pargs.path) stage_git = Git(self.app.pargs.destination) live_url = live_wp.site_url() stage_url = stage_wp.site_url() if self.app.pargs.file_changes or self.app.pargs.all_changes: if stage_git.has_changes(): self.app.log.info("Commiting all changes to staging") stage_git.commit('staging changes') self.app.log.info("Merging staging changes") # TODO do we prefer changes to live or staging.. hrmm live_git.git_ignore(exclude_media=True, exclude_live_archives=True) shell.cmd("cd %s && for i in $(git ls-files . --exclude-standard --others); do rm -rf \"$i\"; done" % self.app.pargs.path) live_git.cmd('reset', '--hard') live_git.cmd('merge', '-X theirs staging') else: self.app.log.info("No file changes were found to commit") if self.app.pargs.db_changes or self.app.pargs.all_changes: stage_sql_file = stage_wp.db_export() live_wp.db_import(stage_sql_file) os.unlink(stage_sql_file) live_wp.rename(stage_url, live_url) live_wp.cli('core update-db') live_wp.cli('cache flush') @ex( help='delete a staging environment', arguments=[ ] ) def delete(self): destination = self.app.pargs.destination live_git = Git(self.app.pargs.path) stage_git = Git(self.app.pargs.destination) live_git.wipe() stage_git.wipe() if os.path.isdir(destination): self.app.log.info("Clearing destination %s" % destination) for root, dirs, files in os.walk(destination): for f in files: os.unlink(os.path.join(root, f)) for d in dirs: if os.path.islink(os.path.join(root, d)): os.unlink(os.path.join(root, d)) else: shutil.rmtree(os.path.join(root, d)) Save