running silent, running deep
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2005, TUBITAK/UEKAE
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# Please read the COPYING file.
|
||||
#
|
||||
|
||||
# Specfile module is our handler for PSPEC files. PSPEC (PISI SPEC)
|
||||
# files are specification files for PISI source packages. This module
|
||||
# provides read and write access to PSPEC files.
|
||||
|
||||
# Authors: Eray Ozkural <eray@uludag.org.tr>
|
||||
# Baris Metin <baris@uludag.org.tr>
|
||||
|
||||
# standard python modules
|
||||
from os.path import basename
|
||||
|
||||
# pisi modules
|
||||
from pisi.xmlext import *
|
||||
import pisi.xmlfile as xmlfile
|
||||
from pisi.xmlfile import XmlFile
|
||||
from pisi.ui import ui
|
||||
from pisi.dependency import DepInfo
|
||||
from pisi.util import Checks
|
||||
|
||||
|
||||
class Packager:
|
||||
__metaclass__ = xmlfile.autoxml
|
||||
t_Name = [types.StringType, xmlfile.mandatory]
|
||||
t_Email = [types.StringType, xmlfile.mandatory]
|
||||
def __str__(self):
|
||||
s = "%s <%s>" % (self.name, self.email)
|
||||
return s
|
||||
class AdditionalFileInfo:
|
||||
__metaclass__ = xmlfile.autoxml
|
||||
|
||||
s_Filename = xmlfile.mandatory
|
||||
a_Target = [types.StringType, xmlfile.mandatory]
|
||||
a_Permission = [types.StringType, xmlfile.optional]
|
||||
|
||||
def __str__(self):
|
||||
s = "%s -> %s " % (self.filename, self.target)
|
||||
if self.permission:
|
||||
s += '(%s)' % self.permission
|
||||
return s
|
||||
|
||||
class Patch:
|
||||
__metaclass__ = xmlfile.autoxml
|
||||
|
||||
s_Filename = xmlfile.mandatory
|
||||
a_compressionType = [types.StringType, xmlfile.optional]
|
||||
a_level = [types.StringType, xmlfile.optional]
|
||||
a_target = [types.StringType, xmlfile.optional]
|
||||
|
||||
def __str__(self):
|
||||
s = self.filename
|
||||
if self.compressionType:
|
||||
s += ' (' + self.compressionType + ')'
|
||||
if self.level:
|
||||
s += ' level:' + self.level
|
||||
if self.target:
|
||||
s += ' target:' + self.target
|
||||
return s
|
||||
|
||||
class Update:
|
||||
__metaclass__ = xmlfile.autoxml
|
||||
|
||||
t_Date = [types.StringType, xmlfile.mandatory]
|
||||
t_Version = [types.StringType, xmlfile.mandatory]
|
||||
t_Release = [types.StringType, xmlfile.mandatory]
|
||||
t_Type = [types.StringType, xmlfile.optional]
|
||||
|
||||
def __str__(self):
|
||||
s = self.date
|
||||
s += ", ver=" + self.version
|
||||
s += ", rel=" + self.release
|
||||
if self.type:
|
||||
s += ", type=" + self.type
|
||||
return s
|
||||
|
||||
class Path:
|
||||
__metaclass__ = xmlfile.autoxml
|
||||
s_Path = xmlfile.mandatory
|
||||
a_fileType = [types.StringType, xmlfile.optional]
|
||||
def __str__(self):
|
||||
s = self.pathname
|
||||
s += ", type=" + self.fileType
|
||||
return s
|
||||
|
||||
|
||||
class ComarProvide:
|
||||
__metaclass__ = xmlfile.autoxml
|
||||
s_om = [types.StringType, xmlfile.mandatory]
|
||||
a_script = [types.StringType, xmlfile.mandatory]
|
||||
def __str__(self):
|
||||
# FIXME: descriptive enough?
|
||||
s = self.script
|
||||
s += ' (' + self.om + ')'
|
||||
return s
|
||||
|
||||
class Archive:
|
||||
__metaclass__ = xmlfile.autoxml
|
||||
s_uri = [ types.StringType, xmlfile.mandatory ]
|
||||
a_type =[ types.StringType, xmlfile.mandatory ]
|
||||
a_sha1sum =[ types.StringType, xmlfile.mandatory ]
|
||||
|
||||
def decode_post(self):
|
||||
self.name = basename(self.uri)
|
||||
|
||||
|
||||
class Source:
|
||||
__metaclass__ = xmlfile.autoxml
|
||||
t_Name = [types.StringType, xmlfile.mandatory]
|
||||
t_HomePage = [types.StringType, xmlfile.mandatory]
|
||||
t_Packager = [Packager, xmlfile.mandatory]
|
||||
t_Summary = [types.StringType, xmlfile.mandatory]
|
||||
t_Description = [types.StringType, xmlfile.mandatory]
|
||||
t_License = [ [types.StringType], xmlfile.mandatory]
|
||||
t_IsA = [ [types.StringType], xmlfile.mandatory]
|
||||
t_PartOf = [types.StringType, xmlfile.mandatory]
|
||||
t_Archive = [Archive, xmlfile.mandatory ]
|
||||
t_Patch = [ [Patch], xmlfile.mandatory, "Patches/Patch"]
|
||||
t_BuildDep = [ [Dependency], xmlfile.mandatory, "BuildDependencies/Dependency"]
|
||||
t_History = [ [Update], xmlfile.mandatory, "History/Update"]
|
||||
|
||||
|
||||
class Package:
|
||||
__metaclass__ = xmlfile.autoxml
|
||||
t_Name = [ types.StringType, xmlfile.mandatory ]
|
||||
t_Summary = [ types.StringType, xmlfile.mandatory ]
|
||||
t_Description = [ types.StringType, xmlfile.mandatory ]
|
||||
t_IsA = [ [types.StringType], xmlfile.mandatory]
|
||||
t_PartOf = [types.StringType, xmlfile.mandatory]
|
||||
t_History = [ [Update], xmlfile.mandatory, "History/Update"]
|
||||
t_Conflicts = [ [types.StringType], xmlfile.mandatory, "Conflicts/Package"]
|
||||
t_ProvidesComar = [ [ComarProvide], xmlfile.mandatory, "Provides/COMAR"]
|
||||
t_RequriesComar = [ [types.StringType], xmlfile.mandatory, "Requires/COMAR"]
|
||||
t_AdditionalFiles = [ [AdditionalFile], xmlfile.mandatory, "AdditionalFiles/AdditionalFile"]
|
||||
|
||||
+7
-6
@@ -9,17 +9,19 @@
|
||||
#
|
||||
# Please read the COPYING file.
|
||||
#
|
||||
# some helper functions for using minidom
|
||||
# works well enough for now... :/
|
||||
# function names are mixedCase for compatibility with minidom,
|
||||
# an old library
|
||||
|
||||
# Authors: Eray Ozkural <eray@uludag.org.tr>
|
||||
# Baris Metin <baris@uludag.org.tr
|
||||
|
||||
"""
|
||||
some helper functions for using minidom
|
||||
function names are mixedCase for compatibility with minidom,
|
||||
an old library
|
||||
"""
|
||||
|
||||
import pisi
|
||||
|
||||
class XmlError(pisi.Error):
|
||||
"named this way because the class if mostly used with an import *"
|
||||
pass
|
||||
|
||||
def getNodeAttribute(node, attrname):
|
||||
@@ -105,7 +107,6 @@ def getAllNodes(node, tagPath):
|
||||
|
||||
return nodeList
|
||||
|
||||
|
||||
def createTagPath(dom, node, tags):
|
||||
"""create new child at the end of a tag chain starting from node
|
||||
no matter what"""
|
||||
|
||||
+167
-31
@@ -9,35 +9,47 @@
|
||||
#
|
||||
# Please read the COPYING file.
|
||||
#
|
||||
# XmlFile is a halper module for accessing XML files using
|
||||
# xml.dom.minidom.
|
||||
#
|
||||
# XmlFile class that further abstracts a dom object using the
|
||||
# high-level dom functions provided in xml module (and sorely lacking
|
||||
# in xml.dom :( )
|
||||
#
|
||||
# method names are mixedCase for compatibility with minidom,
|
||||
# an old library
|
||||
|
||||
# Authors: Eray Ozkural <eray@uludag.org.tr>
|
||||
# Baris Metin <baris@uludag.org.tr
|
||||
|
||||
|
||||
"""
|
||||
xmlfile is a helper module for accessing XML files using
|
||||
xml.dom.minidom.
|
||||
|
||||
XmlFile class further abstracts a dom object using the
|
||||
high-level dom functions provided in xmlext module (and sorely lacking
|
||||
in xml.dom :( )
|
||||
|
||||
autoxml is a metaclass for automatic XML translation, using
|
||||
a miniature type system
|
||||
|
||||
Method names are mixedCase for compatibility with minidom,
|
||||
an old library
|
||||
"""
|
||||
|
||||
# System
|
||||
import xml.dom.minidom as mdom
|
||||
from xml.parsers.expat import ExpatError
|
||||
import codecs
|
||||
|
||||
from xmlext import *
|
||||
|
||||
# PiSi
|
||||
import pisi
|
||||
from pisi.xmlext import *
|
||||
|
||||
|
||||
class Error(pisi.Error):
|
||||
pass
|
||||
|
||||
|
||||
import types
|
||||
|
||||
mandatory, optional = range(2)
|
||||
|
||||
|
||||
class autoxml(type):
|
||||
"high-level automatic XML transformation interface for xmlfile"
|
||||
|
||||
def __init__(cls, name, bases, dict):
|
||||
|
||||
@@ -50,36 +62,160 @@ class autoxml(type):
|
||||
super(autoxml, cls).__init__(name, bases, dict)
|
||||
|
||||
# initialize class attribute __xml_tags
|
||||
setattr(cls, '__xml_tags', [])
|
||||
#setattr(cls, 'xml_variables', [])
|
||||
|
||||
# find variables that start with x_
|
||||
if not dict.has_key('tag'):
|
||||
setattr(cls, 'tag', name)
|
||||
|
||||
root_tag = cls.tag
|
||||
|
||||
# generate helper routines
|
||||
initializers = []
|
||||
decoders = []
|
||||
encoders = []
|
||||
formatters = []
|
||||
for var in dict:
|
||||
if var.startswith('t_'):
|
||||
print 'xml tag', var
|
||||
autoxml.gen_tag(cls, var[2:])
|
||||
if var.startswith('t_') or var.startswith('a_'):
|
||||
name = var[2:]
|
||||
#print 'name', name
|
||||
# possible python bug, binds var only to t_Email here!
|
||||
## def initializer(self):
|
||||
## print 'got', name
|
||||
## setattr(self, name, None)
|
||||
## initializers.append(initializer)
|
||||
initializers.append(autoxml.gen_init(cls, name))
|
||||
if var.startswith('t_'):
|
||||
x = autoxml.gen_tag(cls, name)
|
||||
elif var.startswith('a_'):
|
||||
x = autoxml.gen_attr(cls, name)
|
||||
(decoder, encoder, formatter) = x
|
||||
decoders.append(decoder)
|
||||
encoders.append(encoder)
|
||||
formatters.append(formatter)
|
||||
|
||||
#print initializers
|
||||
|
||||
setattr(cls, 'initializers', initializers)
|
||||
def initialize(self):
|
||||
for initializer in self.__class__.initializers:
|
||||
initializer(self)
|
||||
setattr(cls, '__init__', initialize)
|
||||
|
||||
setattr(cls, 'decoders', decoders)
|
||||
def decode(self, node):
|
||||
for decoder in self.__class__.decoders:
|
||||
decoder(self, node)
|
||||
setattr(cls, 'decode', decode)
|
||||
|
||||
setattr(cls, 'encoders', encoders)
|
||||
def encode(self, xml):
|
||||
for encoder in self.__class__.encoders:
|
||||
encoder(self, xml)
|
||||
setattr(cls, 'encode', encode)
|
||||
|
||||
setattr(cls, 'formatters', formatters)
|
||||
def format(self):
|
||||
string = ''
|
||||
for formatter in self.__class__.formatters:
|
||||
string = string + formatter(self)
|
||||
return string
|
||||
setattr(cls, 'format', format)
|
||||
if not dict.has_key('__str__'):
|
||||
def string(self):
|
||||
return self.format()
|
||||
setattr(cls, '__str__', string)
|
||||
|
||||
def gen_init(cls, name):
|
||||
def initializer(self):
|
||||
varname = cls.mixed_case(name)
|
||||
#print 'init:', varname
|
||||
setattr(self, varname, None)
|
||||
return initializer
|
||||
|
||||
def gen_tag(cls, tag):
|
||||
# generate readers and writers for the tag
|
||||
val = getattr(cls, 't_' + tag)
|
||||
tag_type = val[0]
|
||||
if type(tag_type) == type(type):
|
||||
if val[0] == types.IntType:
|
||||
autoxml.gen_int_tag(cls, tag, val)
|
||||
#gen_tag = staticmethod(gen_tag)
|
||||
# basic types
|
||||
return autoxml.gen_basic_tag(cls, tag, val)
|
||||
|
||||
def gen_attr(cls, tag):
|
||||
"generate readers and writers for an attribute"
|
||||
#print 'attr:', tag
|
||||
val = getattr(cls, 'a_' + tag)
|
||||
tag_type = val[0]
|
||||
assert type(tag_type) == type(type)
|
||||
return autoxml.gen_basic_attr(cls, tag, val)
|
||||
|
||||
def mixed_case(cls, identifier):
|
||||
identifier_p = identifier[0].lower() + identifier[1:]
|
||||
return identifier_p
|
||||
|
||||
def gen_int_tag(cls, tag, val):
|
||||
print tag, val
|
||||
name = cls.mixed_case(tag)
|
||||
def read_int(self):
|
||||
self.name = getNodeText(getNode(node, tag))
|
||||
setattr(cls, 'decode' + tag, read_int)
|
||||
def gen_basic(cls, token, val, readtext, writetext):
|
||||
"generate a basic tag or attribute"
|
||||
name = cls.mixed_case(token)
|
||||
token_type = val[0]
|
||||
req = val[1]
|
||||
|
||||
def decode(self, node):
|
||||
text = readtext(node, token)
|
||||
if text:
|
||||
try:
|
||||
value = autoxml.basic_cons_map[token_type](text)
|
||||
except Error:
|
||||
return ['Type mismatch']
|
||||
setattr(self, name, value)
|
||||
else:
|
||||
if req == mandatory:
|
||||
return ['Mandatory argument not available']
|
||||
else:
|
||||
setattr(self, name, None)
|
||||
return None
|
||||
|
||||
def encode(self, xml):
|
||||
node = xml.newNode(cls.tag)
|
||||
if hasattr(self, name):
|
||||
writetext(xml, node, token, str(getattr(self, name)))
|
||||
else:
|
||||
if req == mandatory:
|
||||
return ['Mandatory argument not available']
|
||||
|
||||
def formatter(self):
|
||||
#print 'format:', name
|
||||
if hasattr(self, name):
|
||||
return '%s: %s\n' % (token, str(getattr(self, name)))
|
||||
else:
|
||||
if req == mandatory:
|
||||
raise Error('Mandatory variable %s not available' % name)
|
||||
return ""
|
||||
|
||||
return decode, encode, formatter
|
||||
|
||||
def gen_basic_attr(cls, attr, val):
|
||||
"""generate an attribute with a basic datatype"""
|
||||
def readtext(node, attr):
|
||||
return getNodeAttribute(node, attr)
|
||||
def writetext(xml, node, attr, value):
|
||||
node.setAttribute(attr, value)
|
||||
return autoxml.gen_basic(cls, attr, val, readtext, writetext)
|
||||
|
||||
def gen_basic_tag(cls, tag, val):
|
||||
"""generate a tag with a basic datatype"""
|
||||
def readtext(node, tag):
|
||||
return getNodeText(getNode(node, tag))
|
||||
def writetext(xml, node, tag, value):
|
||||
xml.addTextNodeUnder(node, tag, value)
|
||||
return autoxml.gen_basic(cls, tag, val, readtext, writetext)
|
||||
|
||||
basic_cons_map = {
|
||||
types.StringType : str,
|
||||
types.IntType : int
|
||||
}
|
||||
|
||||
|
||||
class XmlFile(object):
|
||||
"""A class for retrieving information from an XML file"""
|
||||
"""A class to help reading and writing an XML file"""
|
||||
|
||||
def __init__(self, rootTag):
|
||||
self.rootTag = rootTag
|
||||
@@ -98,7 +234,8 @@ class XmlFile(object):
|
||||
try:
|
||||
self.dom = mdom.parse(fileName)
|
||||
except ExpatError, inst:
|
||||
raise XmlError("File '%s' has invalid XML: %s\n" % (fileName, str(inst)))
|
||||
raise Error("File '%s' has invalid XML: %s\n" % (fileName,
|
||||
str(inst)))
|
||||
|
||||
def writexml(self, fileName):
|
||||
f = codecs.open(fileName,'w', "utf-8")
|
||||
@@ -107,7 +244,7 @@ class XmlFile(object):
|
||||
|
||||
def verifyRootTag(self):
|
||||
if self.dom.documentElement.tagName != self.rootTag:
|
||||
raise XmlError("Root tagname not " + self.rootTag + " as expected")
|
||||
raise Error("Root tagname not " + self.rootTag + " as expected")
|
||||
|
||||
# construction helpers
|
||||
|
||||
@@ -156,7 +293,8 @@ class XmlFile(object):
|
||||
""" returns the children of the given path, only with given type """
|
||||
node = self.getNode(tagpath)
|
||||
try:
|
||||
return filter(lambda x:x.nodeType == x.ELEMENT_NODE, node.childNodes)
|
||||
return filter(lambda x:x.nodeType == x.ELEMENT_NODE,
|
||||
node.childNodes)
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
@@ -188,5 +326,3 @@ class XmlFile(object):
|
||||
def addTextNodeUnder(self, node, tagPath, text):
|
||||
"add a text node under given node with tag path (phew)"
|
||||
return self.addNodeUnder(node, tagPath, self.newTextNode(text))
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<A href="http://www.cs.bilkent.edu.tr/~erayo">
|
||||
<Name>Eray Ozkural</Name>
|
||||
<Number>868</Number>
|
||||
</A>
|
||||
+30
-2
@@ -10,19 +10,47 @@
|
||||
|
||||
import unittest
|
||||
import os
|
||||
import xml.dom.minidom as mdom
|
||||
from xml.parsers.expat import ExpatError
|
||||
import types
|
||||
|
||||
from pisi import xmlfile
|
||||
from pisi.config import config
|
||||
import pisi.util as util
|
||||
import types
|
||||
from pisi.xmlext import *
|
||||
|
||||
class XmlFileTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# impl = mdom.getDOMImplementation()
|
||||
pass
|
||||
|
||||
def testMetaClass(self):
|
||||
class A:
|
||||
__metaclass__ = xmlfile.autoxml
|
||||
t_Number = [types.IntType, xmlfile.mandatory]
|
||||
t_Name = [types.StringType, xmlfile.mandatory]
|
||||
t_Number = [types.IntType, xmlfile.optional]
|
||||
t_Email = [types.StringType, xmlfile.optional]
|
||||
a_href = [types.StringType, xmlfile.mandatory]
|
||||
#t_Projects = [ [types.StringType], xmlfile.mandatory]
|
||||
a = A()
|
||||
#print a
|
||||
self.assertEqual(a.href, None)
|
||||
dom = mdom.parse('tests/sandbox/a.xml')
|
||||
node = getNode(dom, 'A')
|
||||
self.assert_(len(A.decoders)>0)
|
||||
a.decode(node)
|
||||
self.assert_(a.href.startswith('http'))
|
||||
self.assertEqual(a.number, 868)
|
||||
self.assertEqual(a.name, 'Eray Ozkural')
|
||||
string = a.format()
|
||||
#print '*', string
|
||||
#self.assert_(string.startswith('Name'))
|
||||
outfn = '/tmp/a2.xml'
|
||||
xml = xmlfile.XmlFile('A')
|
||||
a2 = A()
|
||||
a2.name = "Baris Metin"
|
||||
a2.email = "baris@uludag.org.tr"
|
||||
elt = a2.encode(xml)
|
||||
string = a2.format()
|
||||
|
||||
suite = unittest.makeSuite(XmlFileTestCase)
|
||||
|
||||
Reference in New Issue
Block a user