| | |
| | from __future__ import with_statement |
| | import logging |
| |
|
| |
|
| | logger = logging.getLogger(__name__) |
| |
|
| |
|
| | NS_URI = 'http://openoffice.org/extensions/description/2006' |
| | NS_URI_DEP = 'http://openoffice.org/extensions/description/2006' |
| | NS_URI_XLINK = 'http://www.w3.org/1999/xlink' |
| |
|
| | NS = '{' + NS_URI + '}' |
| | NS_DEP = '{' + NS_URI_DEP + '}' |
| | NS_XLINK = '{' + NS_URI_XLINK + '}' |
| |
|
| |
|
| | def as_dict(f): |
| | def wrapper(*args, **kwargs): |
| | return dict(f(*args, **kwargs)) |
| | wrapper.items = f |
| | return wrapper |
| |
|
| |
|
| | @as_dict |
| | def get_display_name(doc): |
| | root = doc.getroot() |
| | for elt in root.findall(NS + 'display-name/' + NS + 'name'): |
| | yield elt.get('lang'), elt.text |
| |
|
| |
|
| | def set_display_name(doc, display_name): |
| | import xml.etree.ElementTree as ET |
| | root = doc.getroot() |
| | dispname = ET.SubElement(root, 'display-name') |
| | for lang, name in display_name.items(): |
| | elt = ET.SubElement(dispname, 'name') |
| | elt.set('lang', lang) |
| | elt.text = name |
| |
|
| |
|
| | @as_dict |
| | def get_extension_description(doc): |
| | root = doc.getroot() |
| | for elt in root.findall(NS + 'extension-description/' + NS + 'src'): |
| | yield elt.get('lang'), elt.get(NS_XLINK + 'href') |
| |
|
| |
|
| | def set_extension_description(doc, description): |
| | import xml.etree.ElementTree as ET |
| | root = doc.getroot() |
| | desc = ET.SubElement(root, 'extension-description') |
| | for lang, url in description.items(): |
| | elt = ET.SubElement(desc, 'src') |
| | elt.set('lang', lang) |
| | elt.set('xlink:href', url) |
| |
|
| |
|
| | @as_dict |
| | def get_publisher(doc): |
| | root = doc.getroot() |
| | for elt in root.findall(NS + 'publisher/' + NS + 'name'): |
| | yield elt.get('lang'), dict(name=elt.text, |
| | url=elt.get(NS_XLINK + 'href')) |
| |
|
| |
|
| | def set_publisher(doc, publisher): |
| | import xml.etree.ElementTree as ET |
| | root = doc.getroot() |
| | pub = ET.SubElement(root, 'publisher') |
| | for lang, dct in publisher.items(): |
| | elt = ET.SubElement(pub, 'name') |
| | elt.set('lang', lang) |
| | elt.set('xlink:href', dct['url']) |
| | elt.text = dct['name'] |
| |
|
| |
|
| | def get_license_accept_by(doc): |
| | root = doc.getroot() |
| | for elt in root.findall(NS + 'registration/' + NS + 'simple-license'): |
| | accept_by = elt.get('accept-by') |
| | if accept_by: |
| | return accept_by |
| |
|
| |
|
| | def get_license(doc): |
| | root = doc.getroot() |
| | for elt in root.findall(NS + 'registration/' + NS + 'simple-license'): |
| | return dict((elt.get('lang'), elt.get(NS_XLINK + 'href')) |
| | for elt in elt.findall(NS + 'license-text')) |
| | return dict() |
| |
|
| |
|
| | def get_oo_min_version(doc): |
| | root = doc.getroot() |
| | for dep in root.findall(NS + 'dependencies'): |
| | for elt in dep.findall(NS + 'OpenOffice.org-minimal-version'): |
| | return elt.get('value') |
| |
|
| |
|
| | class Description(object): |
| |
|
| | @classmethod |
| | def parse(cls, f): |
| | import xml.etree.ElementTree as ET |
| |
|
| | doc = ET.parse(f) |
| | root = doc.getroot() |
| |
|
| | def getvalue(xpath, default=None): |
| | for elt in root.findall(xpath): |
| | value = elt.get('value', default) |
| | if value: |
| | return value |
| | return default |
| |
|
| | return cls(identifier=getvalue(NS + 'identifier'), |
| | version=getvalue(NS + 'version'), |
| | platform=getvalue(NS + 'platform', 'all'), |
| | display_name=get_display_name(doc), |
| | description=get_extension_description(doc), |
| | publisher=get_publisher(doc), |
| | license_accept_by=get_license_accept_by(doc), |
| | license=get_license(doc), |
| | oo_min_version=get_oo_min_version(doc)) |
| |
|
| | def __init__(self, |
| | identifier='noname', |
| | version='0.0', |
| | platform='all', |
| | display_name=dict(), |
| | description=dict(), |
| | publisher=dict(), |
| | license_accept_by='admin', |
| | license=dict(), |
| | oo_min_version=None): |
| | ''' Generate description.xml |
| | |
| | :param f: output file |
| | :param identifier: extension identifier |
| | :param version: extension version |
| | :param platform: target platform |
| | :param display_name: localizations of display name |
| | :param description: localizations of extension description |
| | :param publisher: localizations of publisher |
| | :param license_accept_by: who is supposed to accept the license |
| | :param license: localization of license |
| | :param oo_min_version: minimal version of LibreOffice |
| | |
| | Each localization parameters are dicts, whose keys are language identifiers |
| | defined in RFC 3066. |
| | |
| | ``identifier`` specifies `Extension Identifier |
| | <http://wiki.openoffice.org/wiki/Documentation/DevGuide/Extensions/Extension_Identifiers>`_. |
| | |
| | ``version`` specifies `Extension Version |
| | <http://wiki.openoffice.org/wiki/Documentation/DevGuide/Extensions/Extension_Versions>`_. |
| | |
| | ``platform`` specifies supposed `Target Platform |
| | <http://wiki.openoffice.org/wiki/Documentation/DevGuide/Extensions/Target_Platform>`_ on which this extension |
| | runs. Default value is ``all``. |
| | |
| | ``display_name`` specifies localized `Display Names |
| | <http://wiki.openoffice.org/wiki/Documentation/DevGuide/Extensions/Display_Name>`_. |
| | It's a localization dict whose values are localized unicode strings, e.g.:: |
| | |
| | display_name = { |
| | 'en': 'Example Filter', |
| | 'ko': u'예제 필터' |
| | } |
| | |
| | Values of ``description`` is a URL of description file, e.g.:: |
| | |
| | description = { |
| | 'en': 'description/en.txt', |
| | 'ko': 'description/ko.txt' |
| | } |
| | |
| | ``publisher`` specifies `Publisher Information |
| | <http://wiki.openoffice.org/wiki/Documentation/DevGuide/Extensions/Publisher_Information>`_. |
| | It's a localization dict whose values are dicts themselves, which have |
| | ``name`` and ``url``. ``name`` is a localized name of the publisher and |
| | ``url`` is a URL of the publisher. For example:: |
| | |
| | publisher = { |
| | 'en': { |
| | 'name': 'John Doe', |
| | 'url': 'http://example.tld' |
| | }, |
| | 'ko': { |
| | 'name': u'홍길동', |
| | 'url': 'http://example.tld' |
| | } |
| | } |
| | |
| | Optional ``license_accept_by`` specifies who is supposed to accept the |
| | license. ``admin`` or ``user``. Default value is 'admin'. |
| | |
| | Optional ``license`` is a localization dict whose values are an URL of |
| | license file. For example:: |
| | |
| | license = { |
| | 'en': 'registration/COPYING' |
| | } |
| | |
| | See `Simple License |
| | <http://wiki.openoffice.org/wiki/Documentation/DevGuide/Extensions/Simple_License>`_. |
| | ''' |
| | self.identifier = identifier |
| | self.version = version |
| | self.platform = platform |
| | self.display_name = display_name |
| | self.description = description |
| | self.publisher = publisher |
| | self.license_accept_by = license_accept_by |
| | self.license = license |
| | self.oo_min_version = oo_min_version |
| |
|
| | def write(self, f): |
| |
|
| | |
| |
|
| | import xml.etree.ElementTree as ET |
| |
|
| | root = ET.Element('description', {'xmlns': NS_URI, |
| | 'xmlns:dep': NS_URI_DEP, |
| | 'xmlns:xlink': NS_URI_XLINK}) |
| | doc = ET.ElementTree(root) |
| |
|
| | ET.SubElement(root, 'identifier').set('value', self.identifier) |
| | ET.SubElement(root, 'version').set('value', self.version) |
| | ET.SubElement(root, 'platform').set('value', self.platform) |
| |
|
| | set_display_name(doc, self.display_name) |
| |
|
| | set_extension_description(doc, self.description) |
| |
|
| | set_publisher(doc, self.publisher) |
| |
|
| | if self.license: |
| | reg = ET.SubElement(root, 'registration') |
| | lic = ET.SubElement(reg, 'simple-license') |
| | lic.set('accept-by', self.license_accept_by) |
| | for lang, url in self.license.items(): |
| | elt = ET.SubElement(lic, 'license-text') |
| | elt.set('lang', lang) |
| | elt.set('xlink:href', url) |
| |
|
| | if self.oo_min_version is not None: |
| | dep = ET.SubElement(root, 'dependencies') |
| | minver = ET.SubElement(dep, 'OpenOffice.org-minimal-version') |
| | minver.set('dep:name', 'LibreOffice ' + self.oo_min_version) |
| | minver.set('value', self.oo_min_version) |
| |
|
| | f.write('<?xml version="1.0" encoding="utf-8"?>') |
| | doc.write(f, encoding='utf-8') |
| |
|
| | def required_files(self): |
| | for url in self.description.values(): |
| | yield url |
| | for url in self.license.values(): |
| | yield url |
| |
|
| |
|
| | def print_human_readable(desc, root_stg=None): |
| | ''' Print summary in human readable form. |
| | |
| | :param desc: an instance of Description |
| | :param root_stg: root storage of description.xml |
| | ''' |
| | from storage import resolve_path |
| | print 'identifier:', desc.identifier |
| | print 'version:', desc.version |
| | print 'platform:', desc.platform |
| |
|
| | print 'display-name:' |
| | for lang, name in desc.display_name.items(): |
| | print ' [%s] %s' % (lang, name) |
| |
|
| | print 'extension-description:' |
| | for lang, url in desc.description.items(): |
| | if not root_stg or resolve_path(root_stg, url): |
| | state = '' |
| | else: |
| | state = ' -- MISSING' |
| | print ' [%s] %s%s' % (lang, url, state) |
| |
|
| | print 'publisher:' |
| | for lang, publisher in desc.publisher.items(): |
| | print ' [%s] %s (%s)' % (lang, |
| | publisher['name'], |
| | publisher['url']) |
| | if desc.license: |
| | print 'license: accept-by', desc.license_accept_by |
| | for lang, url in desc.license.items(): |
| | if not root_stg or resolve_path(root_stg, url): |
| | state = '' |
| | else: |
| | state = ' -- MISSING' |
| | print ' [%s] %s%s' % (lang, url, state) |
| |
|
| | if desc.oo_min_version: |
| | print 'dependencies:' |
| | print ' LibreOffice minimal version:', desc.oo_min_version |
| |
|
| |
|
| | def init_main(): |
| | doc = '''Usage: oxt-desc-init [options] <desc-file> |
| | |
| | --help Print this screen. |
| | ''' |
| |
|
| | from docopt import docopt |
| | args = docopt(doc) |
| | logging.basicConfig(level=logging.INFO) |
| |
|
| | description = Description(identifier='tld.example', |
| | version='0.1', |
| | display_name=dict(en='Example extension'), |
| | publisher=dict(en=dict(name='Publisher Name', |
| | url='http://example.tld')), |
| | license=dict(url=dict(en='COPYING')), |
| | description=dict(en='description/en.txt')) |
| | with file(args['<desc-file>'], 'w') as f: |
| | description.write(f) |
| |
|
| |
|
| | def show_main(): |
| | doc = '''Usage: oxt-desc-show [options] <desc-file> |
| | |
| | --help Show this screen. |
| | ''' |
| | from docopt import docopt |
| | args = docopt(doc) |
| | logging.basicConfig(level=logging.INFO) |
| |
|
| | with file(args['<desc-file>']) as f: |
| | desc = Description.parse(f) |
| |
|
| | print_human_readable(desc) |
| |
|
| |
|
| | def version_main(): |
| | doc = '''Usage: oxt-desc-version [options] <desc-file> [<new-version>] |
| | |
| | --help Show this screen. |
| | ''' |
| | from docopt import docopt |
| | args = docopt(doc) |
| | logging.basicConfig(level=logging.INFO) |
| |
|
| | with file(args['<desc-file>'], 'r') as f: |
| | desc = Description.parse(f) |
| |
|
| | new_version = args['<new-version>'] |
| | if new_version is not None: |
| | logger.info('old: %s', desc.version) |
| | desc.version = new_version |
| | logger.info('new: %s', desc.version) |
| | with file(args['<desc-file>'], 'w') as f: |
| | desc.write(f) |
| | else: |
| | print desc.version |
| |
|
| |
|
| | def ls_main(): |
| | doc = '''Usage: oxt-desc-ls [options] <desc-file> |
| | |
| | --help Show this screen. |
| | ''' |
| | from docopt import docopt |
| | args = docopt(doc) |
| | logging.basicConfig(level=logging.INFO) |
| |
|
| | with file(args['<desc-file>']) as f: |
| | desc = Description.parse(f) |
| |
|
| | for path in desc.required_files(): |
| | print path |
| |
|