URL
https://opencores.org/ocsvn/radiohdl/radiohdl/trunk
Subversion Repositories radiohdl
[/] [radiohdl/] [trunk/] [core/] [hdl_raw_access.py] - Rev 4
Compare with Previous | Blame | View Log
############################################################################### # # Copyright (C) 2014-2018 # ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> # P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # # 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 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # # $Id$ # ############################################################################### import re import os.path from configfile import * from configtree import ConfigTree __all__ = ['RawConfigFile', 'RawConfigTree'] """ File that implements the configfile <-> configtree concept but this time with the intention to modify the keys and/or values in those configfiles. So the content of the configfiels is kept as raw as possible. """ class RawConfigFile(object): """ Class that holds the raw content of a configfile. To simplify the manipulation of the content the file is internally stored as lines. """ def __init__(self, filename): """ Read the hdl configuration file and check presence of the required keys. :raise ConfigFileException """ full_filename = os.path.expanduser(os.path.expandvars(filename)) if not os.path.isfile(full_filename): raise ConfigFileException("configfile '%s' not found" % full_filename) self.filename = full_filename self.content = open(self.filename, 'r').readlines() @property def ID(self): "Returns uniq ID (string) to identify this particular file. Fullfilename is used." return self.filename def _save_content(self, verbose=False): """ Write the content to the file. """ with open(self.filename, 'w') as fp: fp.writelines(self.content) if verbose: print(self.filename) def change_value(self, key, new_value, verbose): """ Change the value of the given key. The old value may be empty, be on one or multiple lines. The new value may use \n characters to create a new multiline value. """ # Search the key in the lines prog = re.compile("^{}[ \t]*{}".format(key, CFG_ASSIGNMENT_CHAR)) for (linenr, line) in enumerate(self.content): # search if line starts with this key match = prog.search(line) if not match: continue # replace the value that is on this line with the whole new value value_start = match.end() line = line[0:value_start] + ' ' + new_value.replace("\\n", "\n") + "\n" self.content[linenr] = line # to support removing old multiline values we have to skip lines until we find a # sectionheader|other key|empty line or are at the end of the file linenr += 1 while linenr < len(self.content): if not re.match(r"(\[[a-zA-Z0-9_]+\]|[a-zA-Z0-9_]+[ \t]*{}|^[ \t]*$)".format(CFG_ASSIGNMENT_CHAR), self.content[linenr]): self.content.pop(linenr) else: break self._save_content(verbose) break def append_key_value(self, key, value, verbose): """ Append the given key and value to the end of the configfile. \n characters can be used both in the key and the value to start at a new line. """ self.content.append("{} {} {}\n".format(key.replace("\\n", "\n"), CFG_ASSIGNMENT_CHAR, value.replace("\\n", "\n"))) self._save_content(verbose) def rename_key(self, old_key, new_key, verbose): """ Change the name of a key. """ # Search the key in the lines prog = re.compile("^{}[ \t]*{}".format(old_key, CFG_ASSIGNMENT_CHAR)) for (linenr, line) in enumerate(self.content): # search if line starts with this old_key match = prog.search(line) if not match: continue # change the name of the key value_start = match.end() line = "{} {}{}\n".format(new_key.replace("\\n", "\n"), CFG_ASSIGNMENT_CHAR, line[value_start:]) self.content[linenr] = line self._save_content(verbose) break def remove_key(self, key, verbose): """ Remove a key and value pair from the dictfile. """ # difficulty here is that we can delete the lines immediately because the enumeration over the # file content gets messed up. So we setup the variables first_line and last_line that mark # the part of the list that has to be removed. After the enumeration we cut the lines. # First search the key in the lines searching_key = True last_line = len(self.content) key_mask = re.compile(r"^{}[ \t]*{}".format(key, CFG_ASSIGNMENT_CHAR)) end_of_value_mask = re.compile(r"(\[[a-zA-Z0-9_]+\]|[a-zA-Z0-9_]+[ \t]*{})".format(CFG_ASSIGNMENT_CHAR)) for (linenr, line) in enumerate(self.content): if searching_key: # search if line starts with this key match = key_mask.search(line) if match: first_line = linenr searching_key = False else: # not searching for the key anymore, we now have to find the and of the value. # to support removing old multiline values we have to skip lines until we find a # sectionheader|other key or are at the end of the file if not end_of_value_mask.match(self.content[linenr]): continue last_line = linenr break del self.content[first_line:last_line] self._save_content(verbose) def insert_key_at_linenr(self, new_key, new_value, linenumber, verbose): """ Insert a new key = value pair in the configfile at linenumber. The first line has number 1. """ if linenumber > len(self.content): return self.append_key_value(new_key, new_value, verbose) # Read dict file into string and insert new key = value pair at insertLineNr new_line = "{} {} {}\n".format(new_key.replace("\\n", "\n"), CFG_ASSIGNMENT_CHAR, new_value) self.content.insert(linenumber-1, new_line) self._save_content(verbose) def insert_key_value_before_key(self, new_key, new_value, before_key, verbose): """ Insert a new key = value pair in the configfile just before another key.. """ # Search the key in the lines prog = re.compile("^{}[ \t]*{}".format(before_key, CFG_ASSIGNMENT_CHAR)) for (linenr, line) in enumerate(self.content): # search if line starts with this key match = prog.search(line) if not match: continue return self.insert_key_at_linenr(new_key, new_value, linenr+1, verbose) class RawConfigTree(ConfigTree): """ Class the represents the collection of 'raw content' configfiles. """ def __init__(self, rootdirs, filename, sections=None): """ Read the raw configuration files and stores them in this tree. :raise ConfigFileException """ super(RawConfigTree, self).__init__(rootdirs, filename, sections) def _factory_constructor(self, full_filename): "Function for returning the readin configfile." return RawConfigFile(full_filename)