Created
August 27, 2015 15:44
-
-
Save mikhail/430ad49e1fa6061a67c6 to your computer and use it in GitHub Desktop.
Git -> WordPress draft publisher
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import logging | |
import md5 | |
import optparse | |
import os | |
import re | |
import subprocess | |
import sys | |
from wordpress_xmlrpc import Client, WordPressPost | |
from wordpress_xmlrpc.methods.posts import GetPost, GetPosts, NewPost, EditPost | |
import markdown | |
import xmlrpclib | |
import yaml | |
"""Create new Wordpress Post from meta.yml files. | |
Recursively walk the current_dir directory looking for meta.yml | |
When found - check the specified `slug` and create a post if it's not created. | |
""" | |
log = logging.getLogger('WPPost') | |
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) | |
META_FILE = 'meta.yaml' | |
# Initial option handler to set up the basic application environment. | |
usage = 'usage: %prog <options>' | |
parser = optparse.OptionParser(usage=usage, add_help_option=True) | |
parser.set_defaults(verbose=True) | |
# Job Configuration | |
parser.add_option('-d', '--dry', dest='dry', action='store_true', | |
help='Executes a dry run only.') | |
# Logging Configuration | |
parser.add_option('-l', '--level', dest='level', default='info', | |
help='Set logging level (INFO|WARN|DEBUG|ERROR)') | |
parser.add_option('', '--debug', dest='level_debug', default=False, | |
action='store_true', help='Equivalent to --level=DEBUG') | |
(options, args) = parser.parse_args() | |
def get_hashsum(directory): | |
"""Get a unique hash for the entire directory.""" | |
total_bits = subprocess.Popen( | |
'tar c --exclude .git --exclude "*.log" %s' % directory, | |
shell=True, | |
stdout=subprocess.PIPE).stdout.read() | |
return md5.new(total_bits).hexdigest() | |
def run(): | |
log.info('Connecting to WordPress RPC...') | |
wp = Client('https://engblog.nextdoor.com/xmlrpc.php', | |
os.getenv('WP_USER'), | |
os.getenv('WP_PASS')) | |
try: | |
all_posts = wp.call(GetPosts()) | |
except xmlrpclib.Fault as e: | |
log.critical('Could not fetch WP posts. Reason: %s' % e) | |
return False | |
log.info('Success!') | |
statuses = dict([(p.slug, p) for p in all_posts]) | |
log.info('Finding meta files') | |
exit_status = 0 | |
for current_dir, dirs, files in os.walk('.'): | |
if META_FILE not in files: | |
continue | |
log.debug('Found meta file in %s' % current_dir) | |
meta = yaml.load(open('%s/%s' % (current_dir, META_FILE)).read()) | |
log.debug('Checking content file...') | |
content_file = '%s/%s' % (current_dir, meta['contents']) | |
try: | |
md_content = open(content_file).read() | |
except IOError as e: | |
log.error('Path %s cannot be opened. Reason: %s' % ( | |
content_file, e)) | |
exit_status = exit_status + 1 | |
continue | |
slug = meta['slug'] | |
orig_post = statuses.get(slug) | |
status = None | |
if orig_post: | |
status = orig_post.post_status | |
if status == 'publish': | |
log.info('Slug "%s" is already published. Skipping' % slug) | |
continue | |
if status == 'draft': | |
log.warning('Slug "%s" exists. Editing it.' % slug) | |
post = orig_post | |
elif status is None: | |
log.info('Creating a WP Post for "%s"' % slug) | |
post = WordPressPost() | |
post.custom_fields = [{'key': 'cpa_author', | |
'value': meta['author']}] | |
metaversion = get_hashsum(current_dir) | |
online_version = [str(pair['value']) | |
for pair in post.custom_fields | |
if pair['key'] == 'version'] | |
if len(online_version) == 1 and online_version[0] == metaversion: | |
log.info('Meta version not updated. Skipping.') | |
continue | |
log.info('Version changed to %s. Updating.' % metaversion) | |
# Update the "version" field | |
for f in post.custom_fields: | |
if f['key'] == 'version': | |
f['value'] = metaversion | |
break | |
else: | |
post.custom_fields.extend([{'key': 'version', 'value': metaversion}]) | |
post.title = meta['title'] | |
post.excerpt = meta['summary'] | |
# Custom Post Author plugin | |
post.terms_names = { 'post_tag': meta['tags'] } | |
post.slug = slug | |
# 1) Escape non-unicode. 2) Convert from Markdown 3) Unescape non-unicode | |
html_content = markdown.markdown( | |
md_content.encode('string-escape').replace(r'\n', '\n') | |
).decode('string-escape') | |
# Remove single new lines | |
minified_html = re.sub("([^\n])\n([^\n])", r'\1 \2', html_content) | |
# Convert more than 2 new lines into just 2 | |
minified_html = re.sub('\n{3,}', '\n\n', minified_html) | |
post.content = minified_html | |
log.info('Uploading post "%s" to WordPress...' % slug) | |
log.debug('Checking if post needs to be created or updated.') | |
log.debug(post.__dict__) | |
if hasattr(post, 'id'): | |
log.info('Updating...') | |
if not options.dry: | |
wp.call(EditPost(post.id, post)) | |
else: | |
log.warning('Dry run. Not doing anything.') | |
log.info('Done!') | |
else: | |
log.info('POSTING NEW BLOG!') | |
if not options.dry: | |
pid = wp.call(NewPost(post)) | |
log.debug('Fetching post %s' % pid) | |
post = wp.call(GetPost(pid)) | |
log.info('Created %s' % post.guid) | |
else: | |
log.warning('Dry run. Did not do anything.') | |
exit(exit_status) | |
if __name__ == '__main__': | |
run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment