Revision: 2297
Author: KariHusa
Date: Mon Oct 19 05:40:31 2009
Log: Added the uploading functionality, issue 416
http://code.google.com/p/robotframework/source/detail?r=2297
Modified:
/trunk/tools/libdoc/libdoc.py
=======================================
--- /trunk/tools/libdoc/libdoc.py Mon Oct 19 04:44:53 2009
+++ /trunk/tools/libdoc/libdoc.py Mon Oct 19 05:40:31 2009
@@ -20,15 +20,18 @@
Usage: libdoc.py [options] library_or_resource
This script can generate keyword documentation in HTML or XML. The former
is
-for humans and the latter mainly for Robot Framework IDE and other tools.
+for humans and the latter mainly for RIDE and other tools.
Documentation can be created for both test libraries and resource files.
+*************** TODO! Document uploading *********************
+
Options:
-a --argument value * Possible arguments that a library needs.
-f --format HTML|XML Specifies whether to generate HTML or XML output.
The default value is HTML.
-o --output path Where to write the generated documentation. Can be
- either a directory or a file. The default value is
+ either a directory or a file or server address in
which
+ case the file is uploaded there. The default
value is
the directory where the script is executed from.
-N --name newname Sets the name of the documented library or
resource.
-T --title title Sets the title of the generated HTML
documentation.
@@ -50,6 +53,9 @@
import os
import re
+from httplib import HTTPConnection
+from HTMLParser import HTMLParser
+
from robot.running import TestLibrary, UserLibrary
from robot.serializing import Template, Namespace
from robot.errors import DataError, Information
@@ -61,41 +67,48 @@
def main(args):
- opts, libname = process_arguments(args)
+ try:
+ opts, libname = process_arguments(args)
+ except Information, msg:
+ exit(msg=str(msg))
+ except DataError, err:
+ exit(error=str(err))
try:
library = LibraryDoc(libname, opts['argument'], opts['name'])
except DataError, err:
exit(error=str(err))
outpath = get_outpath(opts['output'], library.name, opts['format'])
- if opts['format'] == 'HTML':
- create_html_doc(library, outpath, opts['title'])
- else:
- create_xml_doc(library, outpath)
+ try:
+ if opts['format'] == 'HTML':
+ create_html_doc(library, outpath, opts['title'])
+ else:
+ create_xml_doc(library, outpath)
+ except DataError, err:
+ exit(error=str(err))
exit(outpath)
def process_arguments(args_list):
argparser = utils.ArgumentParser(__doc__)
- try:
- opts, args = argparser.parse_args(args_list,
pythonpath='pythonpath',
- help='help', unescape='escape',
- check_args=True)
- except Information, msg:
- exit(msg=str(msg))
- except DataError, err:
- exit(error=str(err))
+ opts, args = argparser.parse_args(args_list, pythonpath='pythonpath',
+ help='help', unescape='escape',
+ check_args=True)
if not opts['output']:
opts['output'] = '.'
- opts['output'] = os.path.abspath(opts['output'])
if not opts['format']:
- opts['format'] = 'HTML'
+ opts['format'] = _uploading(opts['output']) and 'XML' or 'HTML'
opts['format'] = opts['format'].upper()
if opts['title']:
opts['title'] = opts['title'].replace('_', ' ')
return opts, args[0]
+def _uploading(output):
+ return output.startswith('http://')
def get_outpath(path, libname, format):
+ if _uploading(path):
+ return path
+ path = os.path.abspath(path)
if os.path.isdir(path):
path = os.path.join(path, '%s.%s' % (libname, format.lower()))
if os.path.exists(path):
@@ -123,9 +136,27 @@
def create_xml_doc(lib, outpath):
+ if _uploading(outpath):
+ upload = outpath
+ outpath = '/tmp/upload.xml' # TODO use temp file module
+ else:
+ upload = None
+ _create_xml_doc(lib, outpath)
+ if upload:
+ upload_xml_doc(outpath, upload)
+ os.remove(outpath)
+
+def upload_xml_doc(file_path, host):
+ try:
+ errors = RFDocUploader().upload(file_path, host)
+ except Exception, err:
+ errors = [str(err)]
+ if errors:
+ raise DataError('Failed to upload
library:\n%s' % '\n'.join(errors))
+
+def _create_xml_doc(lib, outpath):
writer = utils.XmlWriter(outpath)
- writer.start('keywordspec', {'name': lib.name, 'type': lib.type,
- 'generated':
utils.get_timestamp(millissep=None)})
+ writer.start('keywordspec', {'name': lib.name, 'type':
lib.type, 'generated': utils.get_timestamp(millissep=None)})
writer.element('version', lib.version)
writer.element('doc', lib.doc)
_write_keywords_to_xml(writer, 'init', lib.inits)
@@ -147,6 +178,8 @@
def exit(msg=None, error=None):
if msg:
+ if _uploading(msg):
+ msg = 'Library successfully uploaded to ' + msg
sys.stdout.write(msg + '\n')
if error:
sys.stderr.write(error + '\n\nTry --help for usage information.\n')
@@ -167,7 +200,6 @@
class _DocHelper:
-
_name_regexp = re.compile("`(.+?)`")
_list_or_table_regexp = re.compile('^(\d+\.|[-*|]|\[\d+\]) .')
@@ -222,7 +254,6 @@
class PythonLibraryDoc(_DocHelper):
-
type = 'library'
def __init__(self, name, arguments=None, newname=None):
@@ -248,9 +279,8 @@
class ResourceDoc(PythonLibraryDoc):
-
type = 'resource'
-
+
def _import(self, path, arguments):
if arguments:
raise DataError("Resource file cannot take arguments.")
@@ -330,7 +360,6 @@
if utils.is_jython:
class JavaLibraryDoc(_DocHelper):
-
type = 'library'
def __init__(self, path, newname=None):
@@ -391,6 +420,77 @@
self.shortdoc = self.doc and self.doc.splitlines()[0] or ''
+class RFDocUploader(object):
+
+ def upload(self, file_path, host):
+ if host.startswith('http://'):
+ host = host[len('http://'):]
+ xml_file = open(file_path, 'rb')
+ conn = HTTPConnection(host)
+ try:
+ return self._upload(conn, xml_file)
+ finally:
+ xml_file.close()
+ conn.close()
+
+ def _upload(self, host, xml_file):
+ resp = self._post_multipart(host, xml_file)
+ return self._validate_success(resp)
+
+ def _post_multipart(self, conn, xml_file):
+ conn.connect()
+ content_type, body = self._encode_multipart_formdata(xml_file)
+ headers = {'User-Agent': 'libdoc.py', 'Content-Type': content_type}
+ conn.request('POST', '/upload/', body, headers)
+ return conn.getresponse()
+
+ def _encode_multipart_formdata(self, xml_file):
+ boundary = '----------ThIs_Is_tHe_bouNdaRY_$'
+ body = """--%(boundary)s
+Content-Disposition: form-data; name="override"
+
+on
+--%(boundary)s
+Content-Disposition: form-data; name="file"; filename="%(filename)s"
+Content-Type: text/xml
+
+%(content)s
+--%(boundary)s--
+""" % {'boundary': boundary, 'filename': xml_file.name, 'content':
xml_file.read()}
+ content_type = 'multipart/form-data; boundary=%s' % boundary
+ return content_type, body.replace('\n', '\r\n')
+
+ def _validate_success(self, resp):
+ html = resp.read()
+ if resp.status != 200:
+ return [resp.reason.strip()]
+ if 'Successfully uploaded library' in html:
+ return None
+ return _ErrorParser(html).errors
+
+
+class _ErrorParser(HTMLParser):
+
+ def __init__(self, html):
+ HTMLParser.__init__(self)
+ self._inside_errors = False
+ self.errors = []
+ self.feed(html)
+ self.close()
+
+ def handle_starttag(self, tag, attributes):
+ if ('class', 'errorlist') in attributes:
+ self._inside_errors = True
+
+ def handle_endtag(self, tag):
+ if tag == 'ul':
+ self._inside_errors = False
+
+ def handle_data(self, data):
+ if self._inside_errors and data.strip():
+ self.errors.append(data)
+
+
DOCUMENT_TEMPLATE = '''<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>