Univention Bugzilla – Attachment 5190 Details for
Bug 31151
dh-umc-module-* can be used for LDAP-only modules
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Fixes + Cleanup
umc-dev.cleanup (text/plain), 63.81 KB, created by
Philipp Hahn
on 2013-04-24 08:26:33 CEST
(
hide
)
Description:
Fixes + Cleanup
Filename:
MIME Type:
Creator:
Philipp Hahn
Created:
2013-04-24 08:26:33 CEST
Size:
63.81 KB
patch
obsolete
>commit 7bf9dfe3873eb9525cdd79656ab33ab8236a828f >Author: Philipp Hahn <hahn@univention.de> >Date: Tue Apr 23 22:50:21 2013 +0200 > > Bug #99999: umc-dev > > Fix DTD and XSD for UMC module definition > Fix examples to be XML valid. > umc-create-module: Fix command line parsing. > >diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module-category.dtd b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module-category.dtd >new file mode 100644 >index 0000000..3035f41 >--- /dev/null >+++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module-category.dtd >@@ -0,0 +1,23 @@ >+<!-- top level element --> >+<!-- version: onyl 2.0 is allowed --> >+<!ELEMENT umc (categories)> >+<!ATTLIST umc >+ version (2.0) #REQUIRED >+ > >+ >+<!-- definition of categories --> >+<!ELEMENT categories (category+)> >+ >+<!-- a category --> >+<!-- priority: favories=100, monitor=1 --> >+<!ELEMENT category (name+)> >+<!ATTLIST category >+ priority CDATA #REQUIRED >+ id ID #REQUIRED >+ > >+ >+<!-- translated names of vatehory --> >+<!ELEMENT name (#PCDATA)> >+<!ATTLIST name >+ lang CDATA #IMPLIED >+ > >diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.dtd b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.dtd >index 116a0cc..d8637da 100644 >--- a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.dtd >+++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.dtd >@@ -1,7 +1,63 @@ >-<?xml version="1.0" encoding="UTF-8"?> >+<!-- top level element --> >+<!-- version: onyl 2.0 is allowed --> > <!ELEMENT umc (module)> >-<!ELEMENT module (name, description, command)* >+<!ATTLIST umc >+ version (2.0) #REQUIRED >+ > >+ >+<!-- definition of a module --> >+<!-- icon: path fragment for icon --> >+<!-- version: onyl 1.0 is allowed --> >+<!ELEMENT module ((name+, description+)?, flavor*, categories?, command*)> >+<!ATTLIST module >+ id CDATA #REQUIRED >+ icon CDATA #REQUIRED >+ priority CDATA #IMPLIED >+ version (1.0) #REQUIRED >+ translationId ID #IMPLIED >+ > >+ >+<!-- translated names of module --> > <!ELEMENT name (#PCDATA)> >-<!ELEMENT command (description*)> >-<!ELEMENT command (description*)> >+<!ATTLIST name >+ lang CDATA #IMPLIED >+ > >+ >+<!-- translated description for module --> >+<!ELEMENT description (#PCDATA)> >+<!ATTLIST description >+ lang CDATA #IMPLIED >+ > >+ >+<!-- LDAP modules --> >+<!ELEMENT flavor (name,description)?> >+<!ATTLIST flavor >+ icon CDATA #IMPLIED >+ priority CDATA #IMPLIED >+ id CDATA #REQUIRED >+ deactivated (yes|no) "no" >+ > >+ >+<!-- definition of categories --> >+<!ELEMENT categories (category+)> >+<!-- a category --> >+<!-- priority: favories=100, monitor=1 --> >+<!ELEMENT category EMPTY> >+<!ATTLIST category >+ name ID #REQUIRED >+ > >+ >+<!-- mapping from UMC command to Python function --> >+<!-- name: UMC command --> >+<!-- function: Python function name --> >+<!ELEMENT command (description*, return?)> >+<!ATTLIST command >+ name CDATA #REQUIRED >+ function NMTOKEN #REQUIRED >+ > > >+<!-- return value type --> >+<!ELEMENT return EMPTY> >+<!ATTLIST return >+ syntax (Boolean|Dictionary|UCR-Variables|umc-boolean) #REQUIRED >+ > >diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.rng b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.rng >new file mode 100644 >index 0000000..57e545a >--- /dev/null >+++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.rng >@@ -0,0 +1,207 @@ >+<?xml version="1.0"?> >+<rng:grammar >+ xmlns:rng="http://relaxng.org/ns/structure/1.0" >+ xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" >+ ns="" >+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> >+ >+ <a:documentation> >+ Univention Corporate Server Management Console definition. >+ Copyriught 2013 Univention GmbH. >+ </a:documentation> >+ >+ <rng:define name="language"> >+ <a:documentation>Counte_Language code.</a:documentation> >+ <rng:data type="string"> >+ <param name="pattern">[a-z][a-z]_[A-Z][A-Z]</param> >+ </rng:data> >+ </rng:define> >+ >+ <rng:define name="translated"> >+ <a:documentation>Translation to multiple languages.</a:documentation> >+ <rng:optional> >+ <rng:attribute name="lang"> >+ <rng:ref name="language"/> >+ </rng:attribute> >+ </rng:optional> >+ <rng:data type="string"/> >+ </rng:define> >+ >+ <rng:define name="version"> >+ <a:documentation>Version string with major and minor number.</a:documentation> >+ <rng:data type="string"> >+ <rng:param name="pattern">[0-9]+\.[0-9]+</rng:param> >+ </rng:data> >+ </rng:define> >+ >+ <rng:define name="category"> >+ <a:documentation>Category string.</a:documentation> >+ <rng:data type="string"/> >+ </rng:define> >+ >+ <rng:start> >+ <rng:element name="umc"> >+ <a:documentation>Top level element to define either UMC modules or categories.</a:documentation> >+ <rng:choice> >+ <rng:ref name="Module"/> >+ <rng:ref name="Categories"/> >+ </rng:choice> >+ <rng:attribute name="version"> >+ <rng:ref name="version"/> >+ </rng:attribute> >+ </rng:element> >+ </rng:start> >+ >+ <rng:define name="Module"> >+ <rng:element name="module"> >+ <a:documentation>UMC module definition</a:documentation> >+ <rng:interleave> >+ <rng:optional> >+ <rng:oneOrMore> >+ <rng:element name="name"> >+ <rng:ref name="translated"/> >+ </rng:element> >+ </rng:oneOrMore> >+ <rng:oneOrMore> >+ <rng:element name="description"> >+ <rng:ref name="translated"/> >+ </rng:element> >+ </rng:oneOrMore> >+ </rng:optional> >+ <rng:optional> >+ <rng:element name="categories"> >+ <rng:oneOrMore> >+ <rng:element name="category"> >+ <rng:attribute name="name"> >+ <rng:ref name="category"/> >+ </rng:attribute> >+ </rng:element> >+ </rng:oneOrMore> >+ </rng:element> >+ </rng:optional> >+ <rng:zeroOrMore> >+ <rng:choice> >+ <rng:ref name="Flavor"/> >+ <rng:ref name="Command"/> >+ </rng:choice> >+ </rng:zeroOrMore> >+ </rng:interleave> >+ <rng:optional> >+ <rng:attribute name="id"> >+ <rng:data type="string"/> >+ </rng:attribute> >+ </rng:optional> >+ <rng:attribute name="icon"> >+ <rng:data type="string"/> >+ </rng:attribute> >+ <rng:optional> >+ <rng:attribute name="priority"> >+ <rng:data type="integer"/> >+ </rng:attribute> >+ </rng:optional> >+ <rng:attribute name="version"> >+ <rng:ref name="version"/> >+ </rng:attribute> >+ <rng:optional> >+ <rng:attribute name="translationId"> >+ <rng:data type="ID"/> >+ </rng:attribute> >+ </rng:optional> >+ </rng:element> >+ </rng:define> >+ >+ <rng:define name="Flavor"> >+ <rng:element name="flavor"> >+ <a:documentation>Definition of UDM modules.</a:documentation> >+ <rng:attribute name="id"> >+ <rng:data type="string"/> >+ </rng:attribute> >+ <rng:choice> >+ <rng:group> >+ <rng:attribute name="deactivated"> >+ <rng:value>yes</rng:value> >+ </rng:attribute> >+ <rng:empty/> >+ </rng:group> >+ <rng:group> >+ <rng:optional> >+ <rng:attribute name="deactivated"> >+ <rng:value>no</rng:value> >+ </rng:attribute> >+ </rng:optional> >+ <rng:oneOrMore> >+ <rng:element name="name"> >+ <rng:ref name="translated"/> >+ </rng:element> >+ </rng:oneOrMore> >+ <rng:oneOrMore> >+ <rng:element name="description"> >+ <rng:ref name="translated"/> >+ </rng:element> >+ </rng:oneOrMore> >+ <rng:optional> >+ <rng:attribute name="icon"> >+ <rng:data type="string"/> >+ </rng:attribute> >+ </rng:optional> >+ <rng:optional> >+ <rng:attribute name="priority"> >+ <rng:data type="integer"/> >+ </rng:attribute> >+ </rng:optional> >+ </rng:group> >+ </rng:choice> >+ </rng:element> >+ </rng:define> >+ >+ <rng:define name="Command"> >+ <rng:element name="command"> >+ <a:documentation>Definition of UMC command mapping to Python functions.</a:documentation> >+ <rng:zeroOrMore> >+ <rng:element name="description"> >+ <rng:ref name="translated"/> >+ </rng:element> >+ </rng:zeroOrMore> >+ <rng:optional> >+ <rng:element name="return"> >+ <rng:attribute name="syntax"> >+ <rng:choice> >+ <rng:value>Boolean</rng:value> >+ <rng:value>Dictionary</rng:value> >+ <rng:value>UCR-Variables</rng:value> >+ <rng:value>umc-boolean</rng:value> >+ </rng:choice> >+ </rng:attribute> >+ </rng:element> >+ </rng:optional> >+ <rng:attribute name="name"> >+ <rng:data type="string"/> >+ </rng:attribute> >+ <rng:attribute name="function"> >+ <rng:data type="string"/> >+ </rng:attribute> >+ </rng:element> >+ </rng:define> >+ >+ <rng:define name="Categories"> >+ <rng:element name="categories"> >+ <a:documentation>Definition of UMC categories.</a:documentation> >+ <rng:oneOrMore> >+ <rng:element name="category"> >+ <rng:oneOrMore> >+ <rng:element name="name"> >+ <rng:ref name="translated"/> >+ </rng:element> >+ </rng:oneOrMore> >+ <rng:attribute name="priority"> >+ <rng:data type="integer"/> >+ </rng:attribute> >+ <rng:attribute name="id"> >+ <rng:ref name="category"/> >+ </rng:attribute> >+ </rng:element> >+ </rng:oneOrMore> >+ </rng:element> >+ </rng:define> >+ >+</rng:grammar> >diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.xml.example b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.xml.example >index e572219..e1bedb9 100644 >--- a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.xml.example >+++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.xml.example >@@ -1,16 +1,22 @@ > <?xml version="1.0" encoding="UTF-8"?> > <umc version="2.0"> >- <module icon="ucr/module" version="2.0"> >- <name>Univention Configuration Registry</name> >- <name lang="de_DE">Univention Configuration Registry</name> >- <description>Managing UCR variables</description> >- <description lang="de_DE">Verwaltung von UCR-Variablen</description> >- <command name="ucr/set" function="set"> >- <description>Set UCR variables</description> >- <description lang="de_DE">Setzen von UCR-Variablen</description> >- <return> >- <syntax type="umc-boolean"/> >- </return> >- </command> >- </module> >+ <module id="ucr/module" icon="ucr/module" version="1.0" priority="42" translationId="umc-module"> >+ <name>Univention Configuration Registry</name> >+ <name lang="de_DE">Univention Configuration Registry</name> >+ <description>Managing UCR variables</description> >+ <description lang="de_DE">Verwaltung von UCR-Variablen</description> >+ <flavor id="group/module" priority="42" icon="udm-group-module"> >+ <name>UDM Module</name> >+ <description>Module description</description> >+ </flavor> >+ <flavor id="mail/mail" deactivated="yes"/> >+ <categories> >+ <category name="system"/> >+ </categories> >+ <command name="ucr/set" function="set"> >+ <description>Set UCR variables</description> >+ <description lang="de_DE">Setzen von UCR-Variablen</description> >+ <return syntax="umc-boolean"/> >+ </command> >+ </module> > </umc> >diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.xsd b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.xsd >index 841809a..c80dcc3 100644 >--- a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.xsd >+++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/data/umc-module.xsd >@@ -1,8 +1,168 @@ >-<?xml version="1.0" encoding="UTF-8"?> >-<xsd:schema xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" elementFormDefault="qualified"> >- <xsd:element name="umc"> >- <xsd:element name="module"> >- <xsd:attribute >- </xsd:element> >- </xsd:element> >-</xsd:schema> >+<?xml version='1.0' encoding='utf-8'?> >+<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'> >+ >+ <xs:annotation> >+ <xs:documentation xml:lang='en'> >+ Univention Corporate Server Management Console definition. >+ Copyriught 2013 Univention GmbH. >+ </xs:documentation> >+ </xs:annotation> >+ >+ <xs:complexType name='translated'> >+ <xs:annotation> >+ <xs:documentation xml:lang='en'> >+ Translation to multiple languages. >+ </xs:documentation> >+ </xs:annotation> >+ <xs:simpleContent> >+ <xs:extension base='xs:string'> >+ <xs:attribute name='lang' type='xs:language' use='optional'/> >+ </xs:extension> >+ </xs:simpleContent> >+ </xs:complexType> >+ >+ <xs:simpleType name="version"> >+ <xs:annotation> >+ <xs:documentation xml:lang='en'> >+ Version string with major and minor number. >+ </xs:documentation> >+ </xs:annotation> >+ <xs:restriction base="xs:string"> >+ <xs:pattern value="[0-9]+\.[0-9]+"/> >+ </xs:restriction> >+ </xs:simpleType> >+ >+ <xs:simpleType name="category"> >+ <xs:annotation> >+ <xs:documentation xml:lang='en'> >+ Category string. >+ </xs:documentation> >+ </xs:annotation> >+ <xs:restriction base="xs:string"/> >+ </xs:simpleType> >+ >+ <xs:element name='umc'> >+ <xs:annotation> >+ <xs:documentation xml:lang='en'> >+ Top level element to define either UMC modules or categories. >+ </xs:documentation> >+ </xs:annotation> >+ <xs:complexType> >+ <xs:choice> >+ <xs:element ref='module'/> >+ <xs:element ref='categories'/> >+ </xs:choice> >+ <xs:attribute name='version' type='version' use='required' fixed='2.0'/> >+ </xs:complexType> >+ </xs:element> >+ >+ <xs:element name='module'> >+ <xs:annotation> >+ <xs:documentation xml:lang='en'> >+ UMC module definition >+ </xs:documentation> >+ </xs:annotation> >+ <xs:complexType> >+ <xs:sequence> >+ <xs:sequence minOccurs='0' maxOccurs='1'> >+ <xs:element name='name' type='translated' maxOccurs='unbounded'/> >+ <xs:element name='description' type='translated' maxOccurs='unbounded'/> >+ </xs:sequence> >+ <xs:element ref='flavor' minOccurs='0' maxOccurs='unbounded'/> >+ <xs:element name='categories' minOccurs='0' maxOccurs='1'> >+ <xs:complexType> >+ <xs:sequence> >+ <xs:element name='category' maxOccurs='unbounded'> >+ <xs:complexType> >+ <xs:attribute name='name' type='category' use='required'/> >+ </xs:complexType> >+ </xs:element> >+ </xs:sequence> >+ </xs:complexType> >+ </xs:element> >+ <xs:element ref='command' minOccurs='0' maxOccurs='unbounded'/> >+ </xs:sequence> >+ <xs:attribute name='id' type='xs:string' use='optional'/> >+ <xs:attribute name='icon' type='xs:string' use='required'/> >+ <xs:attribute name='priority' type='xs:integer' use='optional'/> >+ <xs:attribute name='version' type='version' use='required' fixed='1.0'/> >+ <xs:attribute name='translationId' type='xs:ID' use='optional'/> >+ </xs:complexType> >+ </xs:element> >+ >+ <xs:element name='flavor'> >+ <xs:annotation> >+ <xs:documentation xml:lang='en'> >+ Definition of UDM modules. >+ </xs:documentation> >+ </xs:annotation> >+ <xs:complexType> >+ <xs:sequence minOccurs='0' maxOccurs='1'> >+ <xs:element name='name' type='translated' maxOccurs='unbounded'/> >+ <xs:element name='description' type='translated' maxOccurs='unbounded'/> >+ </xs:sequence> >+ <xs:attribute name='icon' type='xs:string' use='optional'/> >+ <xs:attribute name='priority' type='xs:integer' use='optional'/> >+ <xs:attribute name='id' type='xs:string' use='required'/> >+ <xs:attribute name='deactivated' use='optional' default='no'> >+ <xs:simpleType> >+ <xs:restriction base='xs:string'> >+ <xs:enumeration value='yes'/> >+ <xs:enumeration value='no'/> >+ </xs:restriction> >+ </xs:simpleType> >+ </xs:attribute> >+ </xs:complexType> >+ </xs:element> >+ >+ <xs:element name='command'> >+ <xs:annotation> >+ <xs:documentation xml:lang='en'> >+ Definition of UMC command mapping to Python functions. >+ </xs:documentation> >+ </xs:annotation> >+ <xs:complexType> >+ <xs:sequence> >+ <xs:element name='description' type='translated' minOccurs='0' maxOccurs='unbounded'/> >+ <xs:element name='return' minOccurs='0' maxOccurs='1'> >+ <xs:complexType> >+ <xs:attribute name='syntax' use='required'> >+ <xs:simpleType> >+ <xs:restriction base='xs:string'> >+ <xs:enumeration value='Boolean'/> >+ <xs:enumeration value='Dictionary'/> >+ <xs:enumeration value='UCR-Variables'/> >+ <xs:enumeration value='umc-boolean'/> >+ </xs:restriction> >+ </xs:simpleType> >+ </xs:attribute> >+ </xs:complexType> >+ </xs:element> >+ </xs:sequence> >+ <xs:attribute name='name' type='xs:string' use='required'/> >+ <xs:attribute name='function' type='xs:string' use='required'/> >+ </xs:complexType> >+ </xs:element> >+ >+ <xs:element name='categories'> >+ <xs:annotation> >+ <xs:documentation xml:lang='en'> >+ Definition of UMC categories. >+ </xs:documentation> >+ </xs:annotation> >+ <xs:complexType> >+ <xs:sequence> >+ <xs:element name='category' maxOccurs='unbounded'> >+ <xs:complexType> >+ <xs:sequence> >+ <xs:element name='name' type='translated' maxOccurs='unbounded'/> >+ </xs:sequence> >+ <xs:attribute name='priority' type='xs:integer' use='required'/> >+ <xs:attribute name='id' type='category' use='required'/> >+ </xs:complexType> >+ </xs:element> >+ </xs:sequence> >+ </xs:complexType> >+ </xs:element> >+ >+</xs:schema> >diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/debian/changelog b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/debian/changelog >index ad1dc47..8e2c6bc 100644 >--- a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/debian/changelog >+++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/debian/changelog >@@ -1,3 +1,11 @@ >+univention-management-console (5.0.62-3) UNRELEASED; urgency=low >+ >+ * Fix DTD and XSD for UMC module definition (Bug #00000) >+ * Fix examples to be XML valid. >+ * umc-create-module: Fix command line parsing. >+ >+ -- Philipp Hahn <hahn@univention.de> Tue, 23 Apr 2013 21:10:02 +0200 >+ > univention-management-console (5.0.62-2) unstable; urgency=low > > * Do not log UNIVENTION_DEBUG_{BEGIN, END} information (Bug #29603) >diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh-umc-module-build b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh-umc-module-build >index b386874..9960270 100755 >--- a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh-umc-module-build >+++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh-umc-module-build >@@ -2,7 +2,11 @@ > # -*- coding: utf-8 -*- > # > # Univention Configuration Registry >-# build UMC module >+""" >+Install UMC modules. It parses a RFC 822 file called >+$(package).umc-modules and installs the specified components of a module >+into the correct directories. >+""" > # > # Copyright 2011-2012 Univention GmbH > # >@@ -31,56 +35,58 @@ > # /usr/share/common-licenses/AGPL-3; if not, see > # <http://www.gnu.org/licenses/>. > >-import os > import sys > from optparse import OptionParser > > import univention.debhelper as dh_ucs >+import univention.dh_umc as dh_umc > >-try: >- sys.path.insert( 0, './dev' ) >- import dh_umc >-except BaseException, e: >- print 'warning:', str( e ) >- import univention.dh_umc as dh_umc >- >-"""Helps installing UMC modules. It parses a RFC 822 file called >-$(package).umc-modules and installs the specified components of a module >-into the correct directories.""" > >-def do_package( package, core ): >+def do_package(package, core): >+ """ >+ Compile translation files for package. >+ """ > try: >- modules = dh_umc.read_modules( package, core ) >- except AttributeError, e: >- print >>sys.stderr, str( e ) >- sys.exit( 1 ) >+ modules = dh_umc.read_modules(package, core) >+ except AttributeError, ex: >+ print >> sys.stderr, ex >+ sys.exit(1) > >- if not options.core: >+ if not core: > # build python PO files > for module in modules: > for po_file in module.python_po_files: >- dh_umc.create_po_file( po_file, package, module.python_files ) >- dh_umc.create_mo_file( po_file ) >+ dh_umc.create_po_file(po_file, package, module.python_files) >+ dh_umc.create_mo_file(po_file ) > > # build javascript PO files > for module in modules: > for po_file in module.js_po_files: > # using python as language seems to work better than perl >- dh_umc.create_po_file( po_file, package, module.js_files, 'python' ) >- dh_umc.create_json_file( po_file ) >+ dh_umc.create_po_file(po_file, package, module.js_files, 'python') >+ dh_umc.create_json_file(po_file) > > # build xml PO files > for module in modules: > for lang, po_file in module.xml_po_files: >- dh_umc.module_xml2po( module, po_file, lang ) >- dh_umc.create_mo_file( po_file ) >+ dh_umc.module_xml2po(module, po_file, lang) >+ dh_umc.create_mo_file(po_file) > > >-if __name__ == '__main__': >+def main(): >+ """ >+ Compile translation files for all packages. >+ """ > # parse all options >- parser = OptionParser( usage = 'usage: %prog [--core]' ) >- parser.add_option( '-c', '--core', action = 'store_true', dest = 'core', help = 'If specified modules without javascript and python code are excepted' ) >+ parser = OptionParser(usage='usage: %prog [--core]') >+ parser.add_option('-c', '--core', >+ action='store_true', dest='core', >+ help='If specified modules without javascript and python code are excepted') > >- ( options, args ) = parser.parse_args() >+ options, _args = parser.parse_args() > for package in dh_ucs.binary_packages(): >- do_package( package, options.core ) >+ do_package(package, options.core) >+ >+ >+if __name__ == '__main__': >+ main() >diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh-umc-module-install b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh-umc-module-install >index 879266e..b16df15 100755 >--- a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh-umc-module-install >+++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh-umc-module-install >@@ -2,7 +2,11 @@ > # -*- coding: utf-8 -*- > # > # Univention Configuration Registry >-# install UMC module >+""" >+Install UMC modules. It parses a RFC 822 file called >+$(package).umc-modules and installs the specified components of a module >+into the correct directories. >+""" > # > # Copyright 2011-2012 Univention GmbH > # >@@ -36,152 +40,231 @@ import sys > from optparse import OptionParser > > import univention.debhelper as dh_ucs >-try: >- sys.path.insert( 0, './dev' ) >- import dh_umc >-except: >- import univention.dh_umc as dh_umc >+import univention.dh_umc as dh_umc > >-"""Helps installing UMC modules. It parses a RFC 822 file called >-$(package).umc-modules and installs the specified components of a module >-into the correct directories.""" > >-def do_package( package, core ): >- try: >- modules = dh_umc.read_modules( package, core ) >- except AttributeError, e: >- print >>sys.stderr, str( e ) >- sys.exit( 1 ) >+def do_python(module, destdir): >+ """ >+ Copy Python module and translation. >+ """ >+ # copy python module >+ py_dir = os.path.join(destdir, 'usr', 'share', 'pyshared', 'univention', >+ 'management', 'console', 'modules', '%(Module)s' % module) >+ dh_ucs.doIt('install', '-d', py_dir) > >- if not modules: >+ filename = None >+ for filename in module.python_files: >+ dh_ucs.doIt('install', >+ '-m', '644', >+ '-t', py_dir, filename) >+ if filename is None: >+ print >> sys.stderr, 'W: no python files found in %s' % (module.python_path,) > return > >- for module in modules: >- # prepare directory >- if not core: >- dh_ucs.doIt( 'install', '-d', 'debian/%(package)s/usr/share/pyshared/univention/management/console/modules/%(Module)s' % module ) >- dh_ucs.doIt( 'install', '-d', 'debian/%(package)s/usr/share/univention-management-console/modules' % module ) >- for lang in dh_umc.LANGUAGES: >- module[ 'lang' ] = lang >- dh_ucs.doIt( 'install', '-d', 'debian/%(package)s/usr/share/locale/%(lang)s/LC_MESSAGES' % module ) >- dh_ucs.doIt( 'install', '-d', 'debian/%(package)s/usr/share/univention-management-console-frontend/js/umc/modules/i18n/%(lang)s' % module ) >+ # copy translation files (python) >+ for lang in dh_umc.LANGUAGES: >+ mo_dir = os.path.join(destdir, 'usr', 'share', 'locale', lang, 'LC_MESSAGES') >+ dh_ucs.doIt('install', '-d', mo_dir) >+ mo_file = os.path.join(module.python_path, '%s.mo' % lang) >+ mo_dest = os.path.join(mo_dir, '%(package)s.mo' % module) >+ dh_ucs.doIt('install', >+ '-m', '644', >+ '-D', mo_file, mo_dest) > >- if module.xml_categories: >- dh_ucs.doIt( 'install', '-d', 'debian/%(package)s/usr/share/univention-management-console/categories' % module ) >- else: >- print >>sys.stderr, 'info: no category definition file' > >- if module.icons is not None and not os.path.isdir( module.icons ): >- print >>sys.stderr, 'error: could not find icon directory %s' % module.icons >+def do_javascript(module, destdir): >+ """ >+ Copy javaScript module and translation. >+ """ >+ # copy javascript files >+ js_base = os.path.join(destdir, 'usr', 'share', >+ 'univention-management-console-frontend', 'js', 'umc', 'modules') > >- if not core: >- # copy python module >- install_python = [] >- for entry in os.listdir( module.python_path ): >- filename = os.path.join( module.python_path, entry ) >- if os.path.isfile( filename ) and entry.endswith( '.py' ): >- install_python.append( filename ) >- if not install_python: >- print >>sys.stderr, 'error: no python files found in %s' % module.python_path >- sys,exit( 1 ) >- install_python.append( 'debian/%(package)s/usr/share/pyshared/univention/management/console/modules/%(Module)s' % module ) >- install_python_command = ['install', '-m', '644'] >- install_python_command.extend(install_python) >- dh_ucs.doIt( *install_python_command ) >- >- # copy javascript files >- for srcFile in module.js_files: >- # get destination path >- destFile = 'debian/%s/usr/share/univention-management-console-frontend/js/umc/modules/%s' % ( package, srcFile[len(module.js_path):] ) >- >- # check whether we need to create the destination dir >- destDir = os.path.dirname(destFile) >- if not os.path.exists( destDir ): >- dh_ucs.doIt( 'install', '-d', destDir ) >- >- # copy the .js file >- dh_ucs.doIt( 'install', '-m', '644', srcFile, destFile ) >- >- # copy html files >- for srcFile in module.html_files: >- # get destination path >- destFile = 'debian/%s/usr/share/univention-management-console-frontend/js/umc/modules/%s' % ( package, srcFile[len(module.js_path):] ) >- # copy the .html file >- dh_ucs.doIt( 'install', srcFile, destFile ) >- >- # copy XML definitions >- dh_ucs.doIt( 'install', module.xml_definition, 'debian/%(package)s/usr/share/univention-management-console/modules' % module ) >- >- if module.xml_categories: >- dh_ucs.doIt( 'install', module.xml_categories, 'debian/%(package)s/usr/share/univention-management-console/categories' % module ) >+ filename = None >+ for filename in module.js_files: >+ js_dest = os.path.join(js_base, filename[len(module.js_path):]) >+ dh_ucs.doIt('install', >+ '-m', '644', >+ '-D', filename, js_dest) >+ if filename is None: >+ print >> sys.stderr, 'W: no javascript files found in %s' % (module.js_path,) >+ return >+ >+ # copy translation files (javascript) >+ for lang in dh_umc.LANGUAGES: >+ json_dir = os.path.join(js_base, 'i18n', lang) >+ dh_ucs.doIt('install', '-d', json_dir) >+ json_file = os.path.join(module.js_path, '%s.json' % (lang,)) >+ json_dest = os.path.join(json_dir, '%(Module)s.json' % module) >+ dh_ucs.doIt('install', >+ '-m', '644', >+ '-D', json_file, json_dest) >+ >+ >+def do_html(module, destdir): >+ """ >+ Copy HTML files. >+ """ >+ html_base = os.path.join(destdir, 'usr', 'share', >+ 'univention-management-console-frontend', 'js', 'umc', 'modules') >+ >+ for filename in module.html_files: >+ html_dest = os.path.join(html_base, filename[len(module.js_path):]) >+ dh_ucs.doIt('install', >+ '-m', '644', >+ '-D', filename, html_dest) >+ >+ >+def do_xml(module, destdir): >+ """ >+ Copy XML definition and translation. >+ """ >+ # copy XML definitions >+ xml_dir = os.path.join(destdir, 'usr', 'share', >+ 'univention-management-console', 'modules') >+ dh_ucs.doIt('install', >+ '-d', xml_dir) >+ dh_ucs.doIt('install', >+ '-m', '644', >+ '-t', xml_dir, module.xml_definition) >+ >+ # copy translation files (xml) >+ for lang in dh_umc.LANGUAGES: >+ mo_dir = os.path.join(destdir, 'usr', 'share', >+ 'univention-management-console', 'i18n', lang) >+ dh_ucs.doIt('install', '-d', mo_dir) >+ mo_file = os.path.join(os.path.dirname(module.xml_definition), >+ '%s.mo' % (lang,)) >+ mo_dest = os.path.join(mo_dir, '%(Module)s.mo' % module) >+ dh_ucs.doIt('install', >+ '-m', '644', >+ '-D', mo_file, mo_dest) >+ >+ >+def do_categories(module, destdir): >+ """ >+ Copy XML categories. >+ """ >+ if not module.xml_categories: >+ print >> sys.stderr, 'I: no category definition file' >+ return >+ >+ # copy XML categories >+ cat_dir = os.path.join(destdir, 'usr', 'share', >+ 'univention-management-console', 'categories') >+ dh_ucs.doIt('install', >+ '-d', cat_dir) >+ dh_ucs.doIt('install', >+ '-m', '644', >+ '-t', cat_dir, module.xml_categories) > >- if not core: >- # copy translation files (python) >- for lang in dh_umc.LANGUAGES: >- mo_file = os.path.join( module.python_path, '%s.mo' % lang ) >- module[ 'lang' ] = lang >- dh_ucs.doIt( 'install', mo_file, 'debian/%(package)s/usr/share/locale/%(lang)s/LC_MESSAGES/%(package)s.mo' % module ) >- >- # copy translation files (javascript) >- for lang in dh_umc.LANGUAGES: >- json_file = os.path.join( module.js_path, '%s.json' % lang ) >- module[ 'lang' ] = lang >- dh_ucs.doIt( 'install', json_file, 'debian/%(package)s/usr/share/univention-management-console-frontend/js/umc/modules/i18n/%(lang)s/%(Module)s.json' % module ) >- >- # copy translation files (xml) >- for lang in dh_umc.LANGUAGES: >- mo_file = os.path.join( os.path.dirname( module.xml_definition ), '%s.mo' % lang ) >- module[ 'lang' ] = lang >- dh_ucs.doIt( 'install', '-D', mo_file, 'debian/%(package)s/usr/share/univention-management-console/i18n/%(lang)s/%(Module)s.mo' % module ) >- >- # join script >- join_script = '%s.inst' % package >- join_dest = 'debian/%s/usr/lib/univention-install' % package >- join_exists = False >- for filename in os.listdir( '.' ): >- if filename.endswith( join_script ): >- join_script = filename >- if not os.path.exists( join_dest ): >- dh_ucs.doIt( 'install', '-d', join_dest ) >- dh_ucs.doIt( 'install', '-t', join_dest, '-m', '755', filename ) >- join_exists = True >- break >+ >+def do_icons(module, destdir): >+ """ >+ Copy icons. >+ """ >+ if module.icons is None: >+ return >+ if not os.path.isdir(module.icons): >+ print >> sys.stderr, 'W: could not find icon directory %s' % (module.icons,) >+ return >+ >+ # copy icons >+ icon_base = os.path.join(destdir, 'usr', 'share', >+ 'univention-management-console-frontend', 'js', 'dijit', 'themes', >+ 'umc', 'icons') >+ for dirname, dirs, files in os.walk(module.icons): >+ if '.svn' in dirs: >+ dirs.remove( '.svn' ) >+ icon_dir = os.path.join(icon_base, dirname[len(module.icons):]) >+ dh_ucs.doIt('install', >+ '-d', icon_dir) >+ for icon in files: >+ dh_ucs.doIt('install', >+ '-m', '644', >+ '-t', icon_dir, os.path.join(dirname, icon)) >+ >+ >+def do_join(package, destdir): >+ """ >+ Copy join script. >+ """ >+ join_dir = os.path.join(destdir, 'usr', 'lib', 'univention-install') >+ for filename in os.listdir('.'): >+ if filename.endswith('%s.inst' % (package,)): >+ dh_ucs.doIt('install', >+ '-d', join_dir) >+ dh_ucs.doIt('install', >+ '-m', '755', >+ '-t', join_dir, filename) >+ return filename >+ return None >+ >+ >+def do_package(package, core): >+ """ >+ Install files for one binary package. >+ """ >+ try: >+ modules = dh_umc.read_modules(package, core) >+ except AttributeError, ex: >+ print >> sys.stderr, ex >+ sys.exit(1) >+ >+ base = os.path.join('debian', package) >+ >+ for module in modules: >+ do_xml(module, base) >+ do_categories(module, base) > > if not core: >- # copy icons >- for dirname, dirs, files in os.walk( module.icons ): >- if '.svn' in dirs: >- dirs.remove( '.svn' ) >- dest = 'debian/%s/usr/share/univention-management-console-frontend/js/dijit/themes/umc/icons/%s' % ( package, dirname[ len( module.icons ) : ] ) >- if not os.path.exists( dest ): >- dh_ucs.doIt( 'install', '-d', dest ) >- for icon in files: >- dh_ucs.doIt( 'install', '-t', dest, '-m', '644', os.path.join( dirname, icon ) ) >- >- f_postinst = open( os.path.join( 'debian', package + '.postinst.debhelper' ), 'a' ) >- if join_exists: >- f_postinst.write( ''' >+ do_python(module, base) >+ do_javascript(module, base) >+ do_html(module, base) >+ do_icons(module, base) >+ >+ join_script = do_join(package, base) >+ >+ f_postinst = open(base + '.postinst.debhelper', 'a') >+ f_postinst.write('# generated by dh-umc-module-install\n') >+ if join_script: >+ f_postinst.write('''\ > # run join script on DC master and DC backup > . /usr/share/univention-lib/base.sh > call_joinscript %s || true >-''' % join_script ) >- f_postinst.write( 'invoke-rc.d univention-management-console-server reload || true\n' ) >- f_postinst.write( ''' >+''' % (join_script,)) >+ f_postinst.write('invoke-rc.d univention-management-console-server reload ' >+ '|| true\n') >+ f_postinst.write('''\ > # generate a new hash for the UMC frontend in order to avoid caching problems > . /usr/share/univention-lib/umc.sh > umc_frontend_new_hash >-''' ) >- f_postinst.close() >+''') >+ f_postinst.close() > >- f_prerm = open( os.path.join( 'debian', package + '.prerm.debhelper' ), 'a' ) >- f_prerm.write( 'invoke-rc.d univention-management-console-server reload || true\n' ) >- f_prerm.close() >+ f_postrm = open(base + '.prerm.debhelper', 'a') >+ f_postrm.write('# generated by dh-umc-module-install\n') >+ f_postrm.write('invoke-rc.d univention-management-console-server reload ' >+ '|| true\n') >+ f_postrm.close() > >-if __name__ == '__main__': >+ >+def main(): >+ """ >+ Install UMC modules. It parses a RFC 822 file called >+ $(package).umc-modules and installs the specified components of a module >+ into the correct directories. >+ """ > # parse all options >- parser = OptionParser( usage = 'usage: %prog [--core]' ) >- parser.add_option( '-c', '--core', action = 'store_true', dest = 'core', help = 'If specified modules without javascript and python code are excepted' ) >+ parser = OptionParser(usage='usage: %prog [--core]') >+ parser.add_option('-c', '--core', >+ action='store_true', dest='core', >+ help='If specified modules without javascript and python code are excepted') > >- ( options, args ) = parser.parse_args() >+ options, _args = parser.parse_args() > for package in dh_ucs.binary_packages(): >- do_package( package, options.core ) >+ do_package(package, options.core) >+ >+ >+if __name__ == '__main__': >+ main() >diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh-umc-translate b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh-umc-translate >index 1b8113b..2b7d933 100755 >--- a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh-umc-translate >+++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh-umc-translate >@@ -2,7 +2,9 @@ > # -*- coding: utf-8 -*- > # > # Univention Configuration Registry >-# build UMC module >+""" >+Tool creates .json files for translation using gettext. >+""" > # > # Copyright 2011-2012 Univention GmbH > # >@@ -32,32 +34,33 @@ > # <http://www.gnu.org/licenses/>. > > import os >-import sys > > from optparse import OptionParser > > import univention.dh_umc as dh_umc >-import univention.debhelper as dh_ucs > >-"""Tool creates .json files for translation using gettext.""" > > def main(): >+ """ >+ Tool creates .json files for translation using gettext. >+ """ > # parse all options >- parser = OptionParser( usage = 'usage: %prog --package <packageName> --outdir <outDir> [options] <jsFile> ...' ) >- parser.add_option( '-p', '--package', action = 'store', >- dest = 'package', >- help = 'Specifies the package name which is needed for the creation of .po files. (Mandatory)' ) >- parser.add_option( '-t', '--type', action = 'store', type = 'choice', choices = ['json', 'mo', 'po', 'core'], >- dest = 'type', default = 'json', >- help = 'Type of the final output file; note that "json" and "mo" will both also create .po files [%default]') >- parser.add_option( '-o', '--outdir', action = 'store', >- dest = 'outdir', >- help = 'Specifies the output directory where translations from all js files are saved to. (Mandatory)') >- parser.add_option( '-l', '--lang', action = 'append', >- dest = 'lang', >- help = 'Specifies the languages that are processed (default: de)') >+ parser = OptionParser(usage='usage: %prog --package <packageName> --outdir <outDir> [options] <jsFile> ...') >+ parser.add_option('-p', '--package', >+ action='store', dest='package', >+ help='Specifies the package name which is needed for the creation of .po files. (Mandatory)') >+ parser.add_option('-t', '--type', >+ action='store', type='choice', choices=('json', 'mo', 'po',), >+ dest='type', default='json', >+ help='Type of the final output file; note that "json" and "mo" will both also create .po files [%default]') >+ parser.add_option('-o', '--outdir', >+ action='store', dest='outdir', >+ help='Specifies the output directory where translations from all js files are saved to. (Mandatory)') >+ parser.add_option('-l', '--lang', >+ action='append', dest='lang', >+ help='Specifies the languages that are processed (default: de)') > >- ( options, args ) = parser.parse_args() >+ options, args = parser.parse_args() > > # # make sure we have javascript files > # if not len(args): >@@ -70,36 +73,28 @@ def main(): > > # make sure we have enough parameters > if not options.package: >- print '\nYou need to specify a package-name (--package) as well as a list of JavaScript files to process!\n' >- sys.exit(1) >+ parser.error('You need to specify a package-name (--package) as well as a list of JavaScript files to process!') > > # make sure that we have an output file specified > if not options.outdir: >- print '\nYou need to specify an output directory (--outdir)!\n' >- sys.exit(1) >+ parser.error('You need to specify an output directory (--outdir)!') > > # set the po/mo/json file names and the correct function for generating the > # final output >- po_file = '%s/%%s.po' % options.outdir >- create_final_output = lambda x: None >- if 'json' == options.type: >- # output is json >- create_final_output = dh_umc.create_json_file >- elif 'mo' == options.type: >- # output is mo >- create_final_output = dh_umc.create_mo_file >- elif 'po' != options.type: >- # invalid output type >- print '\nThe output type needs to be one of the following: ".json", ".mo", ".po"!\n' >- sys.exit(1) >+ create_final_output = { >+ 'json': dh_umc.create_json_file, >+ 'mo': dh_umc.create_mo_file, >+ 'po': lambda x: None, >+ }[options.type] > > # build translation files > for lang in dh_umc.LANGUAGES: >- ipo_file = po_file % lang >+ ipo_file = os.path.join(options.outdir, '%s.po' % (lang,)) > if len(args): > # only re-create po files if javascript files are given >- dh_umc.create_po_file( ipo_file, options.package, args) >- create_final_output( ipo_file) >+ dh_umc.create_po_file(ipo_file, options.package, args) >+ create_final_output(ipo_file) >+ > > if __name__ == '__main__': > main() >diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh_umc.py b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh_umc.py >index 62c3703..642199b 100644 >--- a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh_umc.py >+++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/dh_umc.py >@@ -2,7 +2,29 @@ > # -*- coding: utf-8 -*- > # > # Univention Configuration Registry >-# build UMC module >+""" >+Each module definition contains the following entries: >+ >+ Module: The internal name of the module >+ Python: A directory containing the python module. There must be a subdirectory named like the internal name of the module. >+ Definition: The XML definition of the module >+ Javascript: The directory of the javascript code. In this directory must be a a file called <Module>.js >+ Category: The XML definition of additional categories >+ Icons: A directory containing the icons used by the module. The >+ directory structure must follow the following pattern >+ <weight>x<height>/<icon>.(png|gif) >+ >+The entry Category is optional. >+ >+Example: >+ Module: ucr >+ Python: umc/module >+ Definition: umc/ucr.xml >+ Javascript: umc/js >+ Category: umc/categories/ucr.xml >+ Icons: umc/icons >+""" >+ > # > # Copyright 2011-2012 Univention GmbH > # >@@ -48,7 +70,7 @@ JAVASCRIPT = 'Javascript' > CATEGORY = 'Category' > ICONS = 'Icons' > >-LANGUAGES = ( 'de', ) >+LANGUAGES = ('de',) > > PO_HEADER = 'This file is auto-generated by the dh-umc tools and should not be edited!' > PO_METADATA = { >@@ -64,223 +86,261 @@ PO_METADATA = { > 'Content-Transfer-Encoding' : '8bit' > } > >-"""Each module definition contains the following entries: > >- Module: The internal name of the module >- Python: A directory containing the python module. There must be a subdirectory named like the internal name of the module. >- Definition: The XML definition of the module >- Javascript: The directory of the javascript code. In this directory must be a a file called <Module>.js >- Category: The XML definition of additional categories >- Icons: A directory containing the icons used by the module. The >- directory structure must follow the following pattern >- <weight>x<height>/<icon>.(png|gif) >+class UMC_Module(dict): >+ """ >+ Container for UMC module definition. >+ """ > >-The entry Category is optional. >- >-Example: >- Module: ucr >- Python: umc/module >- Definition: umc/ucr.xml >- Javascript: umc/js >- Category: umc/categories/ucr.xml >- Icons: umc/icons >-""" >- >-class UMC_Module( dict ): >- def __init__( self, *args ): >- dict.__init__( self, *args ) >- for key in ( MODULE, PYTHON, JAVASCRIPT, DEFINITION, CATEGORY, ICONS ): >- if key in self and self[ key ]: >- self[ key ] = self[ key ][ 0 ] >+ def __init__(self, *args): >+ dict.__init__(self, *args) >+ for key in (MODULE, PYTHON, JAVASCRIPT, DEFINITION, CATEGORY, ICONS): >+ if key in self and self[key]: >+ self[key] = self[key][0] > > @property >- def package( self ): >- return self.get( 'package' ) >+ def package(self): >+ """ >+ Return the name of the Debian binary package. >+ """ >+ return self.get('package') > > @property > def python_path( self ): >+ """ >+ Return path to Python UMC directory. >+ """ > return '%(Python)s/%(Module)s/' % self > > @property > def js_path( self ): >+ """ >+ Return path to JavaScript UMC directory. >+ """ > return '%(Javascript)s/' % self > > @property > def js_module_file( self ): >+ """ >+ Return path to main JavaScript file. >+ """ > return '%(Javascript)s/%(Module)s.js' % self > >- def iter_files( self, suffix ): >- for dirname, dirs, files in os.walk( self.js_path ): >+ @staticmethod >+ def _iter_files(base, suffix): >+ """ >+ Iterate over all files below base ending with suffix. >+ """ >+ for dirname, dirs, files in os.walk(base): > # ignore .svn directories > if '.svn' in dirs: >- dirs.remove( '.svn' ) >+ dirs.remove('.svn') > # we are only interested in .js files > for ifile in files: >- if ifile.endswith( suffix ): >+ if ifile.endswith(suffix): > yield os.path.join(dirname, ifile) > > @property >- def js_files( self ): >- return self.iter_files( '.js' ) >- # for dirname, dirs, files in os.walk( self.js_path ): >- # # ignore .svn directories >- # if '.svn' in dirs: >- # dirs.remove( '.svn' ) >- # # we are only interested in .js files >- # for ifile in files: >- # if ifile.endswith('.js'): >- # yield os.path.join(dirname, ifile) >+ def js_files(self): >+ """ >+ Iterate over all JavaScript UMC files. >+ """ >+ return UMC_Module._iter_files(self.js_path, '.js') > > @property >- def html_files( self ): >- return self.iter_files( '.html' ) >- # for dirname, dirs, files in os.walk( self.js_path ): >- # # ignore .svn directories >- # if '.svn' in dirs: >- # dirs.remove( '.svn' ) >- # # we are only interested in .js files >- # for ifile in files: >- # if ifile.endswith('.html'): >- # yield os.path.join(dirname, ifile) >+ def html_files(self): >+ """ >+ Iterate over all JavaScript HTML files. >+ """ >+ return UMC_Module._iter_files(self.js_path, '.html') > > @property >- def module_name( self ): >- return self.__getitem__( MODULE ) >+ def module_name(self): >+ """ >+ Return the name of the UMC module. >+ """ >+ return self.__getitem__(MODULE) > > @property >- def xml_definition( self ): >- return self.get( DEFINITION ) >+ def xml_definition(self): >+ """ >+ Return the path to the XML UMC definition. >+ """ >+ return self.get(DEFINITION) > > @property >- def xml_categories( self ): >+ def xml_categories(self): >+ """ >+ Return the path to the XML file defining categories. >+ """ > if CATEGORY in self: >- return self.get( CATEGORY, '' ) >+ return self.get(CATEGORY, '') > > @property >- def python_files( self ): >- for filename in os.listdir( self.python_path ): >- if not filename.endswith( '.py' ): >- continue >- yield os.path.join( self.python_path, filename ) >+ def python_files(self): >+ """ >+ Iterate over all Python UMC files. >+ """ >+ return UMC_Module._iter_files(self.python_path, '.py') > > @property >- def python_po_files( self ): >+ def python_po_files(self): >+ """ >+ Iterate over all Python UMC message catalogs. >+ """ > path = '%(Python)s/%(Module)s/' % self > for lang in LANGUAGES: > yield os.path.join( path, '%s.po' % lang ) > > @property > def js_po_files( self ): >+ """ >+ Iterate over all JavaScript UMC message catalogs. >+ """ > for lang in LANGUAGES: > yield os.path.join( self.__getitem__( JAVASCRIPT ), '%s.po' % lang ) > > @property >- def xml_po_files( self ): >- if self.xml_definition is None: return >- dirpath = os.path.dirname( self.xml_definition ) >+ def xml_po_files(self): >+ """ >+ Iterate over all XML UMC message catalogs. >+ """ >+ if self.xml_definition is None: >+ return >+ dirpath = os.path.dirname(self.xml_definition) > for lang in LANGUAGES: >- yield ( lang, os.path.join( dirpath, '%s.po' % lang ) ) >+ yield (lang, os.path.join(dirpath, '%s.po' % lang)) > > @property >- def icons( self ): >- return self.get( ICONS ) >+ def icons(self): >+ """ >+ Return path to UMC icon directory. >+ """ >+ return self.get(ICONS) >+ > >-def read_modules( package, core = False ): >+def read_modules(package, core=False): >+ """ >+ Read UMC module definition from debian/<package>.umc-modules. >+ """ > modules = [] > >- file_umc_module = os.path.join( 'debian/', package + '.umc-modules' ) >+ file_umc_module = os.path.join('debian', package + '.umc-modules') > >- if not os.path.isfile( file_umc_module ): >+ if not os.path.isfile(file_umc_module): > return modules > >- f_umc_module = open( file_umc_module, 'r' ) >+ f_umc_module = open(file_umc_module, 'r') > >- for item in dh_ucs.parseRfc822( f_umc_module.read() ): >+ for item in dh_ucs.parseRfc822(f_umc_module.read()): > # required fields > if not core: >- for required in ( MODULE, PYTHON, DEFINITION, JAVASCRIPT ): >- if not required in item or not item[ required ]: >- raise AttributeError( 'UMC module definition incomplete. key %s missing' % required ) >+ for required in (MODULE, PYTHON, DEFINITION, JAVASCRIPT): >+ if not required in item or not item[required]: >+ raise AttributeError('UMC module definition incomplete. key %s missing' % (required,)) > > # single values >- item[ 'package' ] = package >- module = UMC_Module( item ) >+ item['package'] = package >+ module = UMC_Module(item) > if core: > if module.module_name != 'umc-core' or not module.xml_categories: > raise ValueError( 'Module definition does not match core module' ) >- modules.append( module ) >+ modules.append(module) >+ >+ f_umc_module.close() > > return modules > >-def _appendPoEntry( poFile, xmlEntry ): >- """Helper function to access text property of XML elements and to find the >- corresponding po-entry.""" >- if xmlEntry != None: >- poFile.append( polib.POEntry( msgid = xmlEntry.text, msgstr = '' ) ) > >-def module_xml2po( module, po_file, language ): >+def module_xml2po(module, po_file, language): > """Create a PO file the XML definition of an UMC module""" >- message_po = '%s/messages.po' % ( os.path.dirname( po_file ) or '.' ) >- >- po = polib.POFile() >- po.header = PO_HEADER >- po.metadata = copy.copy( PO_METADATA ) >- po.metadata[ 'Project-Id-Version' ] = module.package >- po.metadata[ 'POT-Creation-Date' ] = formatdate( localtime = True ) >- po.metadata[ 'Language' ] = language >- >- if module.xml_definition and os.path.isfile( module.xml_definition ): >- tree = ET.ElementTree( file = module.xml_definition ) >- _appendPoEntry( po, tree.find( 'module/name' ) ) >- _appendPoEntry( po, tree.find( 'module/description' ) ) >- for flavor in tree.findall( 'module/flavor' ): >- _appendPoEntry( po, flavor.find( 'name' ) ) >- _appendPoEntry( po, flavor.find( 'description' ) ) >- >- if module.xml_categories and os.path.isfile( module.xml_categories ): >- tree = ET.ElementTree( file = module.xml_categories ) >- for cat in tree.findall( 'categories/category' ): >- _appendPoEntry( po, cat.find( 'name' ) ) >- >- po.save( message_po ) >- if os.path.isfile( po_file ): >- dh_ucs.doIt( 'msgmerge', '--update', '--sort-output', po_file, message_po ) >- if os.path.isfile( message_po ): >- os.unlink( message_po ) >+ message_pot = '%s/messages.pot' % (os.path.dirname(po_file) or '.',) >+ >+ pot = polib.POFile() >+ pot.header = PO_HEADER >+ pot.metadata = copy.copy(PO_METADATA) >+ pot.metadata['Project-Id-Version'] = module.package >+ pot.metadata['POT-Creation-Date'] = formatdate(localtime=True) >+ pot.metadata['Language'] = language >+ >+ def _append_po_entry(xml_entry): >+ """Helper function to access text property of XML elements and to find the >+ corresponding po-entry.""" >+ if xml_entry is not None: >+ pot.append(polib.POEntry(msgid=xml_entry.text, msgstr='')) >+ >+ if module.xml_definition and os.path.isfile(module.xml_definition): >+ tree = ET.ElementTree(file=module.xml_definition) >+ _append_po_entry(tree.find('module/name')) >+ _append_po_entry(tree.find('module/description')) >+ for flavor in tree.findall('module/flavor'): >+ _append_po_entry(flavor.find('name')) >+ _append_po_entry(flavor.find('description')) >+ >+ if module.xml_categories and os.path.isfile(module.xml_categories): >+ tree = ET.ElementTree(file=module.xml_categories) >+ for cat in tree.findall('categories/category'): >+ _append_po_entry(cat.find('name')) >+ >+ pot.save(message_pot) >+ >+ if os.path.isfile(po_file): >+ dh_ucs.doIt('msgmerge', '--update', '--sort-output', po_file, message_pot) >+ if os.path.isfile(message_pot): >+ os.unlink(message_pot) > else: >- dh_ucs.doIt( 'mv', message_po, po_file ) >+ dh_ucs.doIt('mv', message_pot, po_file) >+ > >-def create_po_file( po_file, package, files, language = 'python' ): >+def create_po_file(po_file, package, files, language='python'): > """Create a PO file for a defined set of files""" >- message_po = '%s/messages.po' % ( os.path.dirname( po_file ) or '.' ) >- >- if os.path.isfile( message_po ): >- os.unlink( message_po ) >- if isinstance( files, basestring ): >- files = [ files ] >- dh_ucs.doIt( 'xgettext', '--force-po', '--from-code=UTF-8', '--sort-output', '--package-name=%s' % package, '--msgid-bugs-address=packages@univention.de', '--copyright-holder=Univention GmbH', '--language', language, '-o', message_po, *files ) >- po = polib.pofile( message_po ) >- po.header = PO_HEADER >- po.metadata[ 'Content-Type' ] = 'text/plain; charset=UTF-8' >- po.save() >- if os.path.isfile( po_file ): >- dh_ucs.doIt( 'msgmerge', '--update', '--sort-output', po_file, message_po ) >- if os.path.isfile( message_po ): >- os.unlink( message_po ) >+ message_pot = '%s/messages.pot' % (os.path.dirname(po_file) or '.',) >+ >+ if os.path.isfile(message_pot): >+ os.unlink(message_pot) >+ if isinstance(files, basestring): >+ files = [files] >+ dh_ucs.doIt('xgettext', >+ '--force-po', >+ '--from-code=UTF-8', >+ '--sort-output', >+ '--package-name=%s' % (package,), >+ '--msgid-bugs-address=packages@univention.de', >+ '--copyright-holder=Univention GmbH', >+ '--language', language, >+ '-o', message_pot, >+ *files) >+ pot = polib.pofile(message_pot) >+ pot.header = PO_HEADER >+ pot.metadata['Content-Type'] = 'text/plain; charset=UTF-8' >+ pot.save() >+ >+ if os.path.isfile(po_file): >+ dh_ucs.doIt('msgmerge', '--update', '--sort-output', po_file, message_pot) >+ if os.path.isfile(message_pot): >+ os.unlink(message_pot) > else: >- dh_ucs.doIt( 'mv', message_po, po_file ) >+ dh_ucs.doIt('mv', message_pot, po_file) >+ > > def create_mo_file( po_file ): >- dh_ucs.doIt( 'msgfmt', '--check', '--output-file', po_file.replace( '.po', '.mo' ), po_file ) >+ """ >+ Compile textual message catalog to binary message catalog. >+ """ >+ mo_file = po_file.replace('.po', '.mo') >+ dh_ucs.doIt('msgfmt', '--check', '--output-file', mo_file, po_file) >+ > > def create_json_file( po_file ): >- json_file = po_file.replace( '.po', '.json' ) >- json_fd = open( json_file, 'w' ) >- pofile = polib.pofile( po_file ) >+ """ >+ Compile textual message catalog to JSON message catalog. >+ """ >+ json_file = po_file.replace('.po', '.json') >+ pofile = polib.pofile(po_file) > data = {} > for entry in pofile: >- data[ entry.msgid ] = entry.msgstr >+ data[entry.msgid] = entry.msgstr > >- json_fd.write( json.dumps( data ) ) >+ json_fd = open(json_file, 'w') >+ json_fd.write(json.dumps(data)) > json_fd.close() >- >diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/umc-create-module b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/umc-create-module >index 6b89422..0c71623 100755 >--- a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/umc-create-module >+++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/dev/umc-create-module >@@ -31,127 +31,128 @@ > # /usr/share/common-licenses/AGPL-3; if not, see > # <http://www.gnu.org/licenses/>. > >+# default values >+MODULEID= >+MODULENAME="Dummy module" >+MODULEDESC="This is a dummy module" >+PACKAGENAME= >+CATEGORYNAME="system" >+ICONFILE= >+TEMPLATE="grid_with_detailpage" >+NO_DEBIAN= >+ > usage () { > cat <<EOF >-usage: $(basename $0) [<options>...] <moduleID> [<destinationDir>] >+usage: ${0##*/} [<options>...] <moduleID> [<destinationDir>] >+ ${0##*/} --list > >-destination dir: >+destinationDir: > If not given, it defaults to the current working directory. > > options: >+ --list list available templates > --name displayed name of the module > --description verbose module description (shown as tooltip) >- --category category id (default: system) >+ --category category id (default: $CATEGORYNAME) > --package package name > --icon path to SVG icon file >- --list list available templates >- --template name of the template (default: grid_with_detailpage) >+ --template name of the template (default: $TEMPLATE) > --no-debian do not copy debian packages files >- > EOF > } > >-if [ $# -eq 0 -o "$1" == "--help" -o "$1" == "-h" ]; then >- usage >- exit 1 >-fi >- >-function err() { >+err () { > echo >- echo "ERROR: $@" >+ echo "ERROR: $*" > echo "... aborting" > echo > exit 1 > } > >-function warn() { >+warn () { > echo >- echo "WARNING: $@" >+ echo "WARNING: $*" > echo > } > >-KEYS=(MODULEID MODULENAME MODULEDESC PACKAGENAME CATEGORYNAME YEAR) >+SRC_DIR="/usr/share/univention-management-console-dev/umc-module-templates" >+YEAR=$(date +'%Y') > >-function replace_var() { >- str="$1" >- for ikey in ${KEYS[@]}; do >- eval "ival=\${$ikey}" >- str=${str/$ikey/$ival} >+replace_var () { >+ local ikey str="$1" >+ for ikey in MODULEID MODULENAME MODULEDESC PACKAGENAME CATEGORYNAME YEAR >+ do >+ str=${str//$ikey/${!ikey}} > done > echo "$str" > } > >-# default values >-MODULEID=dummy >-MODULENAME="Dummy module" >-MODULEDESC="This is a dummy module" >-PACKAGENAME="" >-CATEGORYNAME="system" >-ICONFILE="" >-DESTDIR="$PWD" >-TEMPLATE="grid_with_detailpage" >-SRC_DIR="/usr/share/univention-management-console-dev/umc-module-templates" >-YEAR=$(date +'%Y') >-NO_DEBIAN="" >- > # parse the CLI parameters >-for iparam in "$@"; do >- case "$iparam" in >+while [ $# -ge 1 ] >+do >+ case "$1" in >+ --help|-h) >+ usgae >+ exit 0 >+ ;; > --name) > MODULENAME="$2" >- shift 2 >+ shift 2 || err "Missing argument" > ;; > --description) > MODULEDESC="$2" >- shift 2 >+ shift 2 || err "Missing argument" > ;; > --category) > CATEGORYNAME="$2" >- shift 2 >+ shift 2 || err "Missing argument" > ;; > --package) > PACKAGENAME="$2" >- shift 2 >+ shift 2 || err "Missing argument" > ;; > --icon) > ICONFILE="$2" >- shift 2 >+ shift 2 || err "Missing argument" > ;; > --template) > TEMPLATE="$2" >- shift 2 >+ shift 2 || err "Missing argument" > ;; > --list) > echo "Available templates:" >- (cd $SRC_DIR && find -maxdepth 1 -type d ! -name debian -a ! -name "." | sed 's,./, ,') >+ find "$SRC_DIR" -maxdepth 1 -name debian -prune -o -type d -printf ' %P\n' > exit 0 > ;; > --no-debian) > NO_DEBIAN="yes" > shift 1 > ;; >+ -*) >+ err "Unknown option: $1" >+ ;; >+ *) >+ MODULEID="$1" >+ break >+ ;; > esac > done > >-SRC="$SRC_DIR/$TEMPLATE" >-if [ ! -d "$SRC" ]; then >- echo "error: unknown template $TEMPLATE" >- exit 1 >-fi >+[ -n "$MODULEID" ] || err "module ID missing!" > >-MODULEID="$1" >-if [ -z "$MODULEID" ]; then >- usage >- echo "error: module ID missing!" >- exit 1 >-fi >+SRC="$SRC_DIR/$TEMPLATE" >+[ -d "$SRC" ] || err "unknown template $TEMPLATE" > >-if [ $# -ge 2 ]; then >- DESTDIR=$(readlink -f "$2") >+if [ $# -ge 1 ] >+then >+ DESTDIR=$(readlink -f "$1") >+else >+ DESTDIR="$PWD" > fi > > # default values >-if [ -z "$PACKAGENAME" ]; then >+if [ -z "$PACKAGENAME" ] >+then > PACKAGENAME=univention-management-console-module-$MODULEID > fi > >@@ -162,28 +163,37 @@ cp -r "$SRC" "$moduleDir" > [ -z "$NO_DEBIAN" ] && cp -r "$SRC_DIR/debian" "$moduleDir" > > # fix directory and file names >-for findParam in "-type d" "-type f"; do >- find "$moduleDir" $findParam | sort -r | while read ipath; do >+for findParam in d f >+do >+ find "$moduleDir" -depth -type "$findParam" | >+ while read ipath >+ do > jpath=$(replace_var "$ipath") > [ "$ipath" != "$jpath" ] && mv "$ipath" "$jpath" > done > done > > # replace file content >-sedParam="" >-for ikey in ${KEYS[@]}; do >+sedParam= >+for ikey in "${KEYS[@]}" >+do > eval "ival=\${$ikey}" > sedParam="${sedParam}s/$ikey/$ival/g; " > done >-sed -i "$sedParam" $(find "$moduleDir" -type f) >+find "$moduleDir" -type f -exec sed -i "$sedParam" {} + > > # create empty changelog > cd "$moduleDir" >-dch --create --package "$PACKAGENAME" --newversion 0.1.0-1 --distribution unstable "Initial release (Bug #XXXXXX)" >+dch --create \ >+ --package "$PACKAGENAME" \ >+ --newversion 0.1.0-1 \ >+ --distribution unstable \ >+ "Initial release (Bug #XXXXXX)" > > # custom icon file > icon="$moduleDir/umc/icons/scalable/$MODULEID.svgz" >-if [ -n "$ICONFILE" ]; then >+if [ -n "$ICONFILE" ] >+then > # we got a custom icon file... remove the default and copy the custom icon > ext=${ICONFILE##*.} > rm -f "$icon" >@@ -192,17 +202,19 @@ if [ -n "$ICONFILE" ]; then > fi > > # scale icons >-for i in 50 16; do >- out="$moduleDir/umc/icons/${i}x${i}/$MODULEID.png" >+for size in 50 16 >+do >+ out="$moduleDir/umc/icons/${size}x${size}/$MODULEID.png" > mkdir -p "${out%/*}" >- if which inkscape > /dev/null 2>&1; then >+ if which inkscape > /dev/null 2>&1 >+ then > # inkscape is available >- inkscape -C -w $i -h $i -e "$out" "$icon" >- elif which convert > /dev/null 2>&1; then >+ inkscape -C -w "$size" -h "$size" -e "$out" "$icon" >+ elif which convert > /dev/null 2>&1 >+ then > # ImageMagick is available >- convert -background none "$icon" -resize "${i}x${i}" "$out" >+ convert -background none "$icon" -resize "${size}x${size}" "$out" > else > warn "Could not find inkscape or ImageMagick to convert SVG icon to PNG format." > fi > done >- >diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/tests/sanitizer/sanitize.xml b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/tests/sanitizer/sanitize.xml >index 0a8fd77..b542ec2 100644 >--- a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/tests/sanitizer/sanitize.xml >+++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/tests/sanitizer/sanitize.xml >@@ -6,21 +6,21 @@ > <categories> > <category name="system"/> > </categories> >- <command name="sanitize/bool" function="bool"></command> >- <command name="sanitize/choices" function="choices"></command> >- <command name="sanitize/dict" function="dict"></command> >- <command name="sanitize/dict_a" function="dict_a"></command> >- <command name="sanitize/email" function="email"></command> >- <command name="sanitize/int" function="int"></command> >- <command name="sanitize/ldapsearch" function="ldapsearch"></command> >- <command name="sanitize/list" function="list"></command> >- <command name="sanitize/list_a" function="list_a"></command> >- <command name="sanitize/mapping" function="mapping"></command> >- <command name="sanitize/pattern" function="pattern"></command> >- <command name="sanitize/search" function="search"></command> >- <command name="sanitize/string" function="string"></command> >- <command name="sanitize/simple" function="simple"></command> >- <command name="sanitize/multi" function="multi"></command> >- <command name="sanitize/upload" function="upload"></command> >+ <command name="sanitize/bool" function="bool"/> >+ <command name="sanitize/choices" function="choices"/> >+ <command name="sanitize/dict" function="dict"/> >+ <command name="sanitize/dict_a" function="dict_a"/> >+ <command name="sanitize/email" function="email"/> >+ <command name="sanitize/int" function="int"/> >+ <command name="sanitize/ldapsearch" function="ldapsearch"/> >+ <command name="sanitize/list" function="list"/> >+ <command name="sanitize/list_a" function="list_a"/> >+ <command name="sanitize/mapping" function="mapping"/> >+ <command name="sanitize/pattern" function="pattern"/> >+ <command name="sanitize/search" function="search"/> >+ <command name="sanitize/string" function="string"/> >+ <command name="sanitize/simple" function="simple"/> >+ <command name="sanitize/multi" function="multi"/> >+ <command name="sanitize/upload" function="upload"/> > </module> > </umc> >diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/umc-module-templates/grid_with_detailpage/umc/MODULEID.xml b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/umc-module-templates/grid_with_detailpage/umc/MODULEID.xml >index e42362d..3a2ff45 100644 >--- a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/umc-module-templates/grid_with_detailpage/umc/MODULEID.xml >+++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/umc-module-templates/grid_with_detailpage/umc/MODULEID.xml >@@ -1,13 +1,13 @@ > <?xml version="1.0" encoding="UTF-8"?> > <umc version="2.0"> > <module id="MODULEID" icon="MODULEID" version="1.0"> >- <name>MODULENAME</name> >- <description>MODULEDESC</description> >- <categories> >- <category name="CATEGORYNAME"/> >- </categories> >- <command name="MODULEID/query" function="query"></command> >- <command name="MODULEID/colors" function="colors"></command> >- <command name="MODULEID/get" function="get"></command> >+ <name>MODULENAME</name> >+ <description>MODULEDESC</description> >+ <categories> >+ <category name="CATEGORYNAME"/> >+ </categories> >+ <command name="MODULEID/query" function="query"/> >+ <command name="MODULEID/colors" function="colors"/> >+ <command name="MODULEID/get" function="get"/> > </module> > </umc> >diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/umc-module-templates/simple_form/umc/MODULEID.xml b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/umc-module-templates/simple_form/umc/MODULEID.xml >index cdb648f..0e8292b 100644 >--- a/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/umc-module-templates/simple_form/umc/MODULEID.xml >+++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-management-console/umc-module-templates/simple_form/umc/MODULEID.xml >@@ -1,15 +1,12 @@ > <?xml version="1.0" encoding="UTF-8"?> > <umc version="2.0"> >- <module id="MODULEID" icon="MODULEID" version="1.0"> >- <name>MODULENAME</name> >- <description>MODULEDESC</description> >- <categories> >- <category name="CATEGORYNAME"/> >- </categories> >- >- <command name="MODULEID/configuration" function="configuration"> >- </command> >- <command name="MODULEID/send" function="send"> >- </command> >- </module> >+ <module id="MODULEID" icon="MODULEID" version="1.0"> >+ <name>MODULENAME</name> >+ <description>MODULEDESC</description> >+ <categories> >+ <category name="CATEGORYNAME"/> >+ </categories> >+ <command name="MODULEID/configuration" function="configuration"/> >+ <command name="MODULEID/send" function="send"/> >+ </module> > </umc>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 31151
: 5190