Phillip Lord wrote:
Stuart Rackham <[email protected]> writes:
Phillip Lord wrote:
[...]
While I am on a roll with mercurial, I've attached another patch; we
discussed this a while back, getting blogpost to read both categories
and status from file.
Thanks for the patch. I haven't forgotten the orginal discussion
http://groups.google.com/group/asciidoc/browse_frm/thread/36ff073c79cbc20a/bc18d5604f2ec4f5
though it probably seemed like it, it was quite a long time ago.
Don't worry, I don't want to sound like a nag, I just thought that a
patch would make the process easier.
Also, if I am practical, I'm effectively running on a fork of the
mercurial version now; versioning makes this possible, but I still run
the risk of getting conflicts.
I've been trying to get my head around it again. Just to summarise (correct me
if I'm wrong):
- The --read-categories option is an alternative to the
--categories=CATEGORIES option, it allows categories to be specified in the
AsciiDoc source file.
- The --read-status option is an alternative to the --publish and --unpublish
options, it allows the publication status be specified in the AsciiDoc source
file.
Both options throw an error if the AsciiDoc source does not have the requested
attribute.
Yep, that's it. In my case, I pretty much always use blogpost with the
"post" command, then let attributes sort everything else out. For me,
this works superbly.
OK, I've come up with a general approach to AsciiDoc attributes that I hope fits
the bill:
- Blogpost always scans AsciiDoc source files for the following blog parameters:
categories, status, title, doctype, posttype.
- The parameters are entered as AsciiDoc attribute entries. The parameter name
prefixed with 'blogpost-' forms the corresponding attribute name e.g.
:blogpost-status: published
:blogpost-categories: blogpost,AsciiDoc,Weblog client,WordPress
- An --attributes=ATTRIBUTES option can be used to enforce selected AsciiDoc
attribute entries. ATTRIBUTES is a comma-separated list of parameter names e.g.
--attributes=status,categories
- Parameter precedence is (from highest to lowest):
1. Command-line options.
2. AsciiDoc attribute entries.
3. Blogpost cache.
Diff attached.
Cheers, Stuart
I'd love to be able to add a "--read-tags" option as well, which does
the same as the read-categories, but as far as I can tell none of the
XML-RPC interfaces support it. Pity.
I can work around all of this, of course; I could write a driver script
that calls blogpost appropriately, but I though others would like the
functionality.
Phil
--
You received this message because you are subscribed to the Google Groups
"asciidoc" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/asciidoc?hl=en.
diff -r 55dcb4418dee -r fcc9c093e444 blogpost.py
--- a/blogpost.py Sat Feb 06 16:34:42 2010 +1300
+++ b/blogpost.py Thu Feb 11 14:23:02 2010 +1300
@@ -11,9 +11,7 @@
import sys
import os
import time
-import subprocess
import StringIO
-import traceback
import re
import xmlrpclib
import pickle
@@ -69,6 +67,9 @@
def infomsg(msg):
print '%s: %s' % (PROG,msg)
+def warning(msg):
+ infomsg('WARNING: '+msg)
+
def die(msg):
errmsg('ERROR: %s' % msg)
sys.exit(1)
@@ -133,6 +134,9 @@
class Blogpost(object):
+ # Valid AsciiDoc attribute blog parameter names (sans the 'blogpost-' prefix).
+ ATTRIBUTE_NAMES = ('categories','status','title','doctype','posttype')
+
def __init__(self, server_url, username, password, options):
# options contains the command-line options attributes.
self.options = options
@@ -153,6 +157,7 @@
self.cache_file = None # Cache file containing persistant blog data.
self.media_dir = None
self.content = None # File-like object containing blog content.
+ self.attributes = {} # AsciiDoc attribute parameter values.
# XML-RPC server.
self.server = None # wordpresslib.WordPressClient.
self.server_url = server_url # WordPress XML-RPC server URL.
@@ -279,6 +284,52 @@
if not self.options.dry_run:
os.unlink(self.cache_file)
+ def get_attributes(self):
+ '''
+ Load blogpost attributes from AsciiDoc blogpost file.
+ Check attribute value validity.
+ '''
+ def check_value(*valid_values):
+ if value not in valid_values:
+ die('%s: line %d: invalid attribute value: blogpost-%s: %s' %
+ (os.path.basename(self.blog_file), lineno, name, value))
+
+ if self.blog_file is None:
+ return
+ if os.path.splitext(self.blog_file)[1].lower() in ('.htm','.html'):
+ return
+ reo = re.compile(r':blogpost-(?P<name>[-\w]+):\s+(?P<value>.*)')
+ lineno = 1
+ for line in open(self.blog_file):
+ mo = re.match(reo, line)
+ if mo:
+ name = mo.group('name')
+ value = mo.group('value').strip()
+ if name in self.ATTRIBUTE_NAMES:
+ self.attributes[name] = value
+ else:
+ warning('%s: line %d: invalid attribute name: blogpost-%s' %
+ (os.path.basename(self.blog_file), lineno, name))
+ if name == 'status':
+ check_value('published','unpublished')
+ elif name == 'doctype':
+ check_value('article','book','manpage')
+ elif name == 'posttype':
+ check_value('page','post')
+ lineno += 1
+
+ def check_attributes(self):
+ '''
+ Check we have the attributes required by the --attributes option.
+ '''
+ if OPTIONS.attributes:
+ for name in OPTIONS.attributes.split(','):
+ if name not in self.ATTRIBUTE_NAMES:
+ die('illegal --attributes name: %s' % name)
+ if name not in self.attributes:
+ die('%s: missing required attribute: blogpost-%s' %
+ (os.path.basename(self.blog_file), name))
+
def process_media(self):
"""
Upload images referenced in the HTML content and replace content urls
@@ -585,6 +636,9 @@
parser = OptionParser(usage='usage: %prog [OPTIONS] COMMAND [BLOG_FILE]',
version='%s %s' % (PROG,VERSION),
description=description)
+ parser.add_option('-a', '--attributes',
+ dest='attributes', default='', metavar='ATTRIBUTES',
+ help='comma separated of list required attribute parameter names')
parser.add_option('-f', '--conf-file',
dest='conf_file', default=None, metavar='CONF_FILE',
help='configuration file')
@@ -663,7 +717,7 @@
if OPTIONS.categories and \
(command not in ('create','update','categories','post')
or (not blog_file or OPTIONS.post_id)):
- die('--categories is inappropriate')
+ die('--categories is not applicable')
# --post-id option checks.
if command not in ('delete','update','categories','post') and OPTIONS.post_id is not None:
die('--post-id is incompatible with %s command' % command)
@@ -698,27 +752,31 @@
blog.media_dir = OPTIONS.media_dir
blog.set_blog_file(blog_file)
blog.load_cache()
+ blog.get_attributes()
+ blog.check_attributes()
+ blog.title = blog.attributes.get('title', blog.title)
if OPTIONS.title is not None:
blog.title = OPTIONS.title
if OPTIONS.post_id is not None:
blog.id = OPTIONS.post_id
+ blog.post_type = blog.attributes.get('posttype', blog.post_type)
if OPTIONS.pages:
- if blog.post_type == 'post':
- infomsg('WARNING: document was previously posted as a post')
blog.post_type = 'page'
if blog.post_type is None:
- blog.post_type = 'post' # Default if not in cache.
+ blog.post_type = 'post' # Default.
+ blog.status = blog.attributes.get('status', blog.status)
if OPTIONS.publish:
blog.status = 'published'
if OPTIONS.unpublish:
blog.status = 'unpublished'
if blog.status is None:
- blog.status = 'published' # Default if not in cache.
+ blog.status = 'published' # Default.
+ blog.doctype = blog.attributes.get('doctype', blog.doctype)
if OPTIONS.doctype is not None:
blog.doctype = OPTIONS.doctype
if blog.doctype is None:
- blog.doctype = 'article' # Default if not in cache.
-
+ blog.doctype = 'article' # Default.
+ OPTIONS.categories = blog.attributes.get('categories', OPTIONS.categories)
# Handle commands.
if command == 'info':
if not os.path.isfile(blog.cache_file):