Ticket #549: unicode-supportv3.diff

File unicode-supportv3.diff, 19.4 KB (added by [email protected]…, 15 years ago)

This version of the patch lets you configure the input and output encoding of all config files at once. The options defaut to python sys.getdefaultencoding.

  • src/lib/Options.py

     
    247247                    cf=('communication', 'agent-port')) 
    248248AGENT_HOST = Option('Remote host', default=False, cmd='-H', odesc='<hostname>') 
    249249 
     250ENCODING = Option('Encoding of cfg files', default=sys.getdefaultencoding(), cmd='-E', odesc='<encoding>', 
     251                  cf=('components', 'encoding')) 
     252 
    250253class OptionParser(OptionSet): 
    251254    '''OptionParser bootstraps option parsing, getting the value of the config file''' 
    252255    def __init__(self, args): 
  • src/lib/Server/Core.py

     
    200200class Core(object): 
    201201    '''The Core object is the container for all Bcfg2 Server logic, and modules''' 
    202202 
    203     def __init__(self, repo, structures, generators, password, svn): 
     203    def __init__(self, repo, structures, generators, password, svn, encoding): 
    204204        object.__init__(self) 
    205205        self.datastore = repo 
    206206        try: 
     
    215215        self.revision = '-1' 
    216216        self.password = password 
    217217        self.svn = svn 
     218        self.encoding = encoding 
    218219        try: 
    219220            if self.svn: 
    220221                self.read_svn_revision() 
  • src/lib/Server/Plugins/Cfg.py

     
    4949        return self.basefile_reg.match(fname) 
    5050 
    5151class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet): 
    52     def __init__(self, basename, path, props, entry_type): 
    53         Bcfg2.Server.Plugin.EntrySet.__init__(self, basename, path, props, entry_type) 
     52    def __init__(self, basename, path, props, entry_type, encoding): 
     53        Bcfg2.Server.Plugin.EntrySet.__init__(self, basename, path, props, entry_type, encoding) 
    5454        self.specific = CfgMatcher(path.split('/')[-1]) 
    5555 
    5656    def sort_by_specific(self, one, other): 
     
    7979        if entry.get('encoding') == 'base64': 
    8080            entry.text = binascii.b2a_base64(data) 
    8181        else: 
    82             entry.text = data             
     82            entry.text = unicode(data, self.encoding) 
    8383        if entry.text in ['', None]: 
    8484            entry.set('empty', 'true') 
    8585 
  • src/lib/Server/Plugins/TGenshi.py

     
    1717 
    1818class TemplateFile: 
    1919    '''Template file creates Genshi template structures for the loaded file''' 
    20     def __init__(self, name, properties, specific): 
     20    def __init__(self, name, properties, specific, encoding): 
    2121        self.name = name 
    2222        self.properties = properties 
    2323        self.specific = specific 
     24        self.encoding = encoding 
    2425        if self.specific.all: 
    2526            matchname = self.name 
    2627        elif self.specific.group: 
     
    5253                name=fname, metadata=metadata, path=self.name, 
    5354                properties=self.properties).filter(removecomment) 
    5455            if isinstance(self.template, TextTemplate): 
    55                 entry.text = stream.render('text') 
     56                textdata = stream.render('text') 
     57                if type(textdata) == unicode: 
     58                    entry.text = textdata 
     59                else: 
     60                    logger.debug("Override encoding of template to %s" % self.encoding) 
     61                    entry.text = unicode(textdata, self.encoding) 
    5662            else: 
    57                 entry.text = stream.render('xml') 
     63                xmldata = stream.render('xml') 
     64                if type(xmldata) == unicode: 
     65                    entry.text = xmldata 
     66                else: 
     67                    logger.debug("Override encoding of template to %s" % self.encoding) 
     68                    entry.text = unicode(xmldata, self.encoding) 
    5869        except TemplateError, terror: 
    5970            logger.error('Genshi template error: %s' % terror) 
    6071            raise Bcfg2.Server.Plugin.PluginExecutionError 
  • src/lib/Server/Plugins/Metadata.py

     
    296296                                          value=self.probedata[client][probe]) 
    297297                for group in self.cgroups[client]: 
    298298                    lxml.etree.SubElement(cx, "Group", name=group) 
    299             data = lxml.etree.tostring(top) 
     299            data = lxml.etree.tostring(top, encoding='UTF-8', xml_declaration=True) 
    300300            try: 
    301301                datafile = open("%s/%s" % (self.data, 'probed.xml'), 'w') 
    302302            except IOError: 
  • src/lib/Server/Plugins/TCheetah.py

     
    99 
    1010class TemplateFile: 
    1111    '''Template file creates Cheetah template structures for the loaded file''' 
    12     def __init__(self, name, properties, specific): 
     12    def __init__(self, name, properties, specific, encoding): 
    1313        self.name = name 
    1414        self.properties = properties 
    1515        self.specific = specific 
     16        self.encoding = encoding 
    1617        self.template = None 
    1718     
    1819    def handle_event(self, event): 
     
    3435        self.template.path = entry.get('realname', entry.get('name')) 
    3536         
    3637        try: 
    37             entry.text = str(self.template) 
     38            if type(self.template) == unicode: 
     39                entry.text = self.template 
     40            else : 
     41                logger.debug("Override encoding of template to %s" % self.encoding) 
     42                entry.text = unicode(str(self.template), self.encoding) 
    3843        except: 
    3944            (a, b, c) = sys.exc_info() 
    4045            msg = traceback.format_exception(a, b, c, limit=2)[-1][:-1] 
  • src/lib/Server/Statistics.py

     
    2828            except IOError, ioerr: 
    2929                self.logger.error("Failed to open %s for writing: %s" % (self.filename + '.new', ioerr)) 
    3030            else: 
    31                 fout.write(lxml.etree.tostring(self.element)) 
     31                fout.write(lxml.etree.tostring(self.element, encoding='UTF-8', xml_declaration=True)) 
    3232                fout.close() 
    3333                os.rename(self.filename + '.new', self.filename) 
    3434                self.dirty = 0 
  • src/lib/Server/Plugin.py

     
    444444        return False 
    445445 
    446446class SpecificData(object): 
    447     def __init__(self, name, _, specific): 
     447    def __init__(self, name, _, specific, encoding): 
    448448        self.name = name 
    449449        self.specific = specific 
    450450 
     
    459459class EntrySet: 
    460460    '''Entry sets deal with the host- and group-specific entries''' 
    461461    ignore = re.compile("^(.*~|\\..*\\.(tmp|sw[px]))$") 
    462     def __init__(self, basename, path, props, entry_type): 
     462    def __init__(self, basename, path, props, entry_type, encoding): 
    463463        self.path = path 
    464464        self.entry_type = entry_type 
    465465        self.entries = {} 
    466466        self.properties = props 
    467467        self.metadata = default_file_metadata.copy() 
    468468        self.infoxml = None 
     469        self.encoding = encoding 
    469470        pattern = '(.*/)?%s(\.((H_(?P<hostname>\S+))|' % basename 
    470471        pattern += '(G(?P<prio>\d+)_(?P<group>\S+))))?$' 
    471472        self.specific = re.compile(pattern) 
     
    509510                return 
    510511            self.entries[event.filename] = self.entry_type(fpath, 
    511512                                                           self.properties, 
    512                                                            spec) 
     513                                                           spec, self.encoding) 
    513514        self.entries[event.filename].handle_event(event) 
    514515 
    515516    def specificity_from_filename(self, fname): 
     
    631632        self.entries = {} 
    632633        self.handles = {} 
    633634        self.AddDirectoryMonitor('') 
     635        self.encoding = core.encoding 
    634636        if self.use_props: 
    635637            try: 
    636638                self.properties = TemplateProperties( \ 
     
    661663                self.entries[ident] = self.es_cls(self.filename_pattern, 
    662664                                                  dirpath, 
    663665                                                  self.properties, 
    664                                                   self.es_child_cls) 
     666                                                  self.es_child_cls, 
     667                                                  self.encoding) 
    665668                self.Entries['ConfigFile'][ident] =  self.entries[ident].bind_entry 
    666669            if not posixpath.isdir(epath): 
    667670                # do not pass through directory events 
  • src/lib/Server/Admin/Pull.py

     
    7070            new_entry['text'] = '\n'.join(difflib.restore(diff.split('\n'), 1)) 
    7171        else: 
    7272            print "found no data::" 
    73             print lxml.etree.tostring(cfentry) 
     73            print lxml.etree.tostring(cfentry, encoding='UTF-8', xml_declaration=True) 
    7474            raise SystemExit(1) 
    7575        return new_entry 
    7676 
  • src/lib/Client/Tools/POSIX.py

     
    320320                self.logger.error("Cannot verify incomplete ConfigFile %s" % (entry.get('name'))) 
    321321                return False 
    322322            tempdata = entry.text 
     323            if type(tempdata) == unicode: 
     324                tempdata = tempdata.encode(self.setup['encoding']) 
    323325        try: 
    324326            content = open(entry.get('name')).read() 
    325327        except IOError, error: 
    326328            self.logger.error("Failed to read %s: %s" % (error.filename, error.strerror)) 
    327329            return False 
     330        # comparaison should be done with figerprints or md5sum so it would be faster 
     331        # for big binary files 
    328332        contentStatus = content == tempdata 
    329333        if not contentStatus: 
    330334            if tbin or not isString(content): 
     
    348352                        break 
    349353                if do_diff: 
    350354                    diff = '\n'.join(rawdiff) 
    351                     entry.set("current_bdiff", binascii.b2a_base64(diff)) 
     355#                    entry.set("current_bdiff", binascii.b2a_base64(diff)) 
     356#                    entry.set("current_diff", diff) 
    352357                    udiff = '\n'.join([x for x in \ 
    353358                                       difflib.unified_diff(content.split('\n'), \ 
    354359                                                            tempdata.split('\n'))]) 
     
    356361                        eudiff = udiff.encode('ascii') 
    357362                    except: 
    358363                        eudiff = "Binary file: no diff printed" 
     364  
    359365                    nqtext = entry.get('qtext', '') 
    360366 
    361367                    if nqtext: 
     
    417423            elif entry.get('empty', 'false') == 'true': 
    418424                filedata = '' 
    419425            else: 
    420                 filedata = entry.text 
     426                if type(entry.text) == unicode: 
     427                    filedata = entry.text.encode(self.setup['encoding']) 
     428                else: 
     429                    filedata = entry.text 
    421430            newfile.write(filedata) 
    422431            newfile.close() 
    423432            try: 
  • src/sbin/bcfg2-ping-sweep

     
    6363                elm.set("pingable",'N') 
    6464 
    6565    fout = open(clientdatapath, 'w') 
    66     fout.write(lxml.etree.tostring(clientElement.getroot())) 
     66    fout.write(lxml.etree.tostring(clientElement.getroot(), encoding='UTF-8', xml_declaration=True)) 
    6767    fout.close() 
    6868                         
  • src/sbin/bcfg2

     
    116116            'agent-background': Bcfg2.Options.CLIENT_BACKGROUND, 
    117117            'key': Bcfg2.Options.SERVER_KEY, 
    118118            'decision-list': DECISION_LIST, 
     119            'encoding': Bcfg2.Options.ENCODING, 
    119120            } 
    120121 
    121122        self.setup = Bcfg2.Options.OptionParser(optinfo) 
     
    244245            if len(probes.findall(".//probe")) > 0: 
    245246                try: 
    246247                    # upload probe responses 
    247                     proxy.RecvProbeData(Bcfg2.Client.XML.tostring(probedata)) 
     248                    proxy.RecvProbeData(Bcfg2.Client.XML.tostring(probedata, encoding='UTF-8', xml_declaration=True)) 
    248249                except: 
    249250                    self.logger.error("Failed to upload probe data", exc_info=1) 
    250251                    raise SystemExit(1) 
     
    293294            feedback = self.tools.GenerateStats() 
    294295 
    295296            try: 
    296                 proxy.RecvStats(Bcfg2.Client.XML.tostring(feedback)) 
     297                proxy.RecvStats(Bcfg2.Client.XML.tostring(feedback, encoding='UTF-8', xml_declaration=True)) 
    297298            except xmlrpclib.Fault: 
    298299                self.logger.error("Failed to upload configuration statistics") 
    299300                raise SystemExit(2) 
  • src/sbin/bcfg2-server

     
    4141 
    4242        try: 
    4343            self.Core = Core(setup['repo'], setup['structures'], 
    44                              setup['generators'], setup['password'], setup['svn']) 
     44                             setup['generators'], setup['password'],  
     45                             setup['svn'], setup['encoding']) 
    4546        except CoreInitError, msg: 
    4647            logger.critical("Fatal error: %s" % (msg)) 
    4748            raise SystemExit, 1 
     
    104105                           if isinstance(p, Bcfg2.Server.Plugin.ProbingPlugin)]: 
    105106                for probe in plugin.GetProbes(meta): 
    106107                    resp.append(probe) 
    107             return tostring(resp) 
     108            return tostring(resp, encoding='UTF-8', xml_declaration=True) 
    108109        except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError: 
    109110            warning = 'Client metadata resolution error for %s; check server log' % address[0] 
    110111            self.logger.warning(warning) 
     
    158159        '''Build config for a client''' 
    159160        try: 
    160161            client = self.Core.metadata.resolve_client(address) 
    161             return tostring(self.Core.BuildConfiguration(client)) 
     162            return tostring(self.Core.BuildConfiguration(client), encoding='UTF-8', xml_declaration=True) 
    162163        except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError: 
    163164            self.logger.warning("Metadata consistency failure for %s" % (address)) 
    164165            raise Fault, (6, "Metadata consistency failure") 
     
    201202                    'location' : Bcfg2.Options.SERVER_LOCATION, 
    202203                    'passwd'   : Bcfg2.Options.SERVER_PASSWORD, 
    203204                    'static'   : Bcfg2.Options.SERVER_STATIC, 
     205                    'encoding' : Bcfg2.Options.ENCODING, 
    204206                    }) 
    205207 
    206208 
  • src/sbin/bcfg2-build-reports

     
    100100            for item in items: 
    101101                channel.append(item) 
    102102 
    103         tree = "<?xml version=\"1.0\"?>" + tostring(rssdata) 
     103        tree = tostring(rssdata, encoding='UTF-8', xml_declaration=True) 
    104104        fil.write(tree) 
    105105        fil.close() 
    106106 
     
    249249 
    250250            #apply XSLT, different ones based on report type, and options 
    251251            if deliverymechanism == 'null-operator': #Special Cases 
    252                 fileout(tostring(ElementTree(procnodereport).getroot()), deliv) 
     252                fileout(tostring(ElementTree(procnodereport).getroot(), encoding='UTF-8', xml_declaration=True), deliv) 
    253253                break 
    254254            transform = delivtype + '-' + deliverymechanism + '.xsl' 
    255255 
     
    301301                                           (toastring, socket.getfqdn(), outputstring) 
    302302                            mail(outputstring, c) #call function to send 
    303303            else: 
    304                 outputstring = tostring(stylesheet.apply(ElementTree(procnodereport)).getroot()) 
     304                outputstring = tostring(stylesheet.apply(ElementTree(procnodereport)).getroot(), encoding='UTF-8', xml_declaration=True) 
    305305                if deliverymechanism == 'rss': 
    306306                    rss(outputstring, deliv, reprt) 
    307307                else: # must be deliverymechanism == 'www': 
  • src/sbin/bcfg2-info

     
    2323        print fstring % row 
    2424 
    2525class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): 
    26     def __init__(self, repo, struct, gens, passwd, svn): 
     26    def __init__(self, repo, struct, gens, passwd, svn, encoding): 
    2727        cmd.Cmd.__init__(self) 
    2828        try: 
    29             Bcfg2.Server.Core.Core.__init__(self, repo, struct, gens, passwd, svn) 
     29            Bcfg2.Server.Core.Core.__init__(self, repo, struct, gens, passwd, svn, encoding) 
    3030        except Bcfg2.Server.Core.CoreInitError, msg: 
    3131            print "Core load failed because %s" % msg 
    3232            raise SystemExit(1) 
     
    9797        if len(args.split()) == 2: 
    9898            client, ofile = args.split() 
    9999            output = open(ofile, 'w') 
    100             data = lxml.etree.tostring(self.BuildConfiguration(client)) 
     100            data = lxml.etree.tostring(self.BuildConfiguration(client), encoding='UTF-8', xml_declaration=True) 
    101101            output.write(data) 
    102102            output.close() 
    103103        else: 
     
    121121            entry = lxml.etree.Element('ConfigFile', name=fname) 
    122122            metadata = self.metadata.get_metadata(client) 
    123123            self.Bind(entry, metadata) 
    124             print lxml.etree.tostring(entry) 
     124            print lxml.etree.tostring(entry, encoding="UTF-8", xml_declaration=True) 
    125125        else: 
    126126            print 'Usage: buildfile filename hostname' 
    127127 
     
    271271                    'svn': Bcfg2.Options.SERVER_SVN, 
    272272                    'structures': Bcfg2.Options.SERVER_STRUCTURES, 
    273273                    'generators': Bcfg2.Options.SERVER_GENERATORS, 
    274                     'password': Bcfg2.Options.SERVER_PASSWORD}) 
     274                    'password': Bcfg2.Options.SERVER_PASSWORD, 
     275                    'encoding': Bcfg2.Options.ENCODING}) 
    275276    setup = Bcfg2.Options.OptionParser(optinfo) 
    276277    setup.parse(sys.argv[1:]) 
    277278 
    278279    loop = infoCore(setup['repo'], setup['structures'], setup['generators'], 
    279                     setup['password'], setup['svn']) 
     280                    setup['password'], setup['svn'], setup['encoding']) 
    280281    loop.plugins['Metadata'] 
    281282    if "args" in setup and setup['args']: 
    282283        loop.onecmd(" ".join(setup['args']))