def create_userconfig(): """Copies template for user config to USER_CONFIG If user config already exists, do nothing :raise: FileNotFoundError """ if os.path.exists(USER_CONFIG): return import shutil tmpldir = os.path.join(os.path.dirname(__file__), "template") cfgtmpl = os.path.join(tmpldir, "config") # From http://stackoverflow.com/a/600612 try: os.makedirs(os.path.dirname(USER_CONFIG)) log.debug("UserConfig: Created directory for %s", USER_CONFIG) except OSError as err: import errno if not (err.errno == errno.EEXIST and os.path.isdir(tmpldir)): raise shutil.copyfile(cfgtmpl, USER_CONFIG) log.debug("UserConfig: Copied template %s to %s", cfgtmpl, USER_CONFIG)
def indent_dm(self): """Indents only dm:docmanager element and its children""" logmgr_flog() dmindent=' ' dm = self.__tree.find("//dm:docmanager", namespaces=NS) log.debug("dm is %s", dm) if dm is None: return log.debug("-----") info = dm.getparent() #.getprevious() log.info("info: %s", info) prev = info.getprevious() log.info("prev: %s", prev) parent = info.getparent() log.info("parent of info: %s", parent) log.info("child of info: %s", info.getchildren()) if info.tail is None: info.tail = "" infoindent = "".join(info.tail.split('\n')) prev = dm.getprevious() #log.info("prev: %s", prev) if prev is not None: log.info("prev: %s", prev) prev.tail = '\n' + infoindent indent=self.get_indentation(dm.getprevious()) dm.text = '\n' + indent + ' ' dm.tail = '\n' + infoindent for node in dm.iterchildren(): i = dmindent if node.getnext() is not None else '' node.tail = '\n' + indent + i
def set(self, arguments): """Set key/value pairs from arguments :param list arguments: List of arguments with key=value pairs """ logmgr_flog() # count all valid and invalid xml files validfiles, invalidfiles = self.get_files_status(self.__xml) # split key and value args = [i.split("=") for i in arguments] # iter through all key and values for f in self.__files: if "error" in self.__xml[f]: print("[ {} ] {} -> {}".format(red("error"), f, red(self.__xml[f]['errorstr']))) else: for arg in args: try: key, value = arg if key == "languages": value = value.split(",") value = ",".join( self.remove_duplicate_langcodes(value)) log.debug( "[%s] Trying to set value for property " "%r to %r.", f, key, value) if self.__args.bugtracker: self.__xml[f]["handler"].set( {"bugtracker/" + key: value}) else: self.__xml[f]["handler"].set({key: value}) except ValueError: log.error('Invalid usage. ' 'Set values with the following format: ' 'property=value') sys.exit(ReturnCodes.E_INVALID_USAGE_KEYVAL) print("[ {} ] Set data for file {}.".format(green("ok"), f)) # save the changes for f in self.__files: if "error" not in self.__xml[f]: log.debug("[%s] Trying to save the changes.", f) self.__xml[f]["handler"].write() # print the statistics output print( "\nWrote {} valid XML file{} and skipped {} XML file{} due to errors." .format(green(validfiles), '' if validfiles == 1 else 's', red(invalidfiles), '' if invalidfiles == 1 else 's')) if invalidfiles > 0: sys.exit(ReturnCodes.E_SOME_FILES_WERE_INVALID)
def parse(self): logmgr_flog() action = self.__args.action if hasattr(self, action) and getattr(self, action) is not None: log.debug("Action.__init__: %s", self.__args) return getattr(self, action)(self.__args.properties) else: log.error("Method \"%s\" is not implemented.", action) sys.exit(ReturnCodes.E_METHOD_NOT_IMPLEMENTED)
def create_group(self): """Creates the docmanager group element""" logmgr_flog() #search the info-element if not exists raise an error info = self.__tree.find("//d:info", namespaces=NS) # TODO: We need to check for a --force option if info is None: log.debug("No <info> element found!") pos = findinfo_pos(self.__root) log.debug("Using position %d", pos) info = etree.Element("{%s}info" % NS["d"]) info.tail = '\n' info.text = '\n' self.__root.insert(pos, info) log.debug("Adding <info> element in '%s'", self.filename) log.debug("Adding <dm:docmanager> to <info>") # dm = etree.Element("{%s}docmanager" % NS["dm"]) # self.__docmanager = info.insert(0, dm) self.__docmanager = etree.SubElement(info, "{{{dm}}}docmanager".format(**NS), nsmap={'dm': NS['dm']}, )
def __init__(self, filename, stoponerror=True): """Initializes the XmlHandler class :param str filename: filename of XML file """ logmgr_flog() log.debug("Initialized a new XML Handler for file %r.", filename) # general self._filename = "" self._buffer = None # StringIO # file util self._fileutil = FileUtil(filename) # prolog self._offset = 0 self._header = "" self._root = "" self.roottag = "" # parser self.__xmlparser = None self.invalidfile = False self.fileerror = "" self.xmlerrorstring = "" self.stoponerror = stoponerror # lxml self.__tree = None self.__root = None self.__docmanager = None # load the file into a StringIO buffer self._filename = filename self._buffer = ensurefileobj(self._filename) # log self.xmllogerrorstring = "" # parse the given file with lxml self.parse()
def write(self): """Write XML tree to original filename""" logmgr_flog() # Only indent docmanager child elements self.indent_dm() log.debug("root: %s", repr(self._root)) with open(self._filename, 'w') as f: info = self.__root.find("d:info", namespaces=NS) xml_indent(info, 2) content = recover_entities(etree.tostring(self.__tree, \ encoding='unicode', \ # doctype=self._header.rstrip()) )) # self._offset, self._header, self._root, self._roottag starttag = compilestarttag(self._roottag) content = starttag.sub(lambda _: self._root.rstrip(), content, 1) # log.debug("content: %s", repr(content)) f.write(self._header.rstrip()+"\n" + content)
def docmanagerconfig(cfgfiles=None, include_etc=True): """Read DocManager configuration files. The following files are searched for and its configuration is merged together (in this order, from lowest to highest): * /etc/docmanager/config * $XDG_CONFIG_HOME/docmanager/docmanager.config if not found, falls back to ~/.config/docmanager/docmanager.config * GIT_REPO_DIR/.git/docmanager.conf (GIT_REPO_DIR is retrieved by the command `git rev-parse --show-toplevel`) * DOCMANAGER_GIT_REPO/etc/config See the XDG Base Directory Specification: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html :param list cfgfiles: your own list of configfiles :param bool include_etc: Should the develop(!) 'etc/' directory included? Only useful for development :return: merged configuration object :rtype: configparser.ConfigParser """ # Start with the global ones configfiles = GLOBAL_CONFIG[:] if cfgfiles is None: # We need to assemble our configuration file list # # Append user config; env variable XDG_CONFIG_HOME is used if set configfiles.append(USER_CONFIG) # Append config when a .git repo is found gitcfg = get_git_repo_config() if gitcfg: configfiles.append(gitcfg) else: log.debug("Using own config file %s", cfgfiles) # In case the user passes its own config file list, use it but # take care, it's a list: if isinstance(cfgfiles, str): configfiles = [cfgfiles] else: configfiles = cfgfiles # Support pyvenv virtual environments; add it as a last item # # See http://stackoverflow.com/a/1883251 if (cfgfiles is None) and include_etc and hasattr(sys, 'base_prefix'): #dd = os.path.dirname(__file__) #cc = os.path.join(dd, BASECONFIG_NAME) #configfiles.append(cc) #log.debug("Running inside a virtual env, using %s", cc) # # When code with __file__ is packed inside a zipfile, it can no longer # assume that __file__ or __path__ contain filenames or directory # names, and so it will fail (see also PEP 302) # # As such: # 1. First try to use pkg_resources from setuptools (which is installed # anyway in a virtual Python environment) # 2. If that doesn't work, fallback to the __file__ method # # Source: # http://peak.telecommunity.com/DevCenter/PythonEggs#accessing-package-resources # try: from pkg_resources import resource_filename cc = resource_filename(__name__, BASECONFIG_NAME) configfiles.append(cc) except ImportError: # Use fallback method dd = os.path.dirname(__file__) cc = os.path.join(dd, BASECONFIG_NAME) configfiles.append(cc) log.info("Running inside a virtual env, using %r", configfiles[-1]) config = ConfigParser() x = config.read(configfiles) if not x: raise DMConfigFileNotFound(configfiles) # Save state of configuration files config.configfiles = configfiles config.usedconfigfile = x log.debug("All configfiles %s", configfiles) log.debug("Used config file: %s", x) return config
def parse(self): """This function parses the whole XML file """ logmgr_flog() # find the prolog of the XML file (everything before the start tag) try: prolog = findprolog(self._buffer) except SAXParseException as err: self.invalidfile = True self.fileerror = "<{}:{}> {} in {!r}.".format(\ err.getLineNumber(), \ err.getColumnNumber(), \ err.getMessage(), \ self.filename,) if self.stoponerror: raise DMXmlParseError(self.fileerror, ReturnCodes.E_XML_PARSE_ERROR) if not self.invalidfile: # save prolog details self._offset, self._header, self._root, self._roottag = prolog['offset'], \ prolog['header'], \ prolog['root'], \ prolog['roottag'] # replace any entities self.replace_entities() # register namespace # etree.register_namespace("dm", "{dm}".format(**NS)) self.__xmlparser = etree.XMLParser(remove_blank_text=False, resolve_entities=False, dtd_validation=False) # load the file and set a reference to the dm group try: self.__tree = etree.parse(self._buffer, self.__xmlparser) except etree.XMLSyntaxError as err: self.invalidfile = True self.fileerror = err.msg if self.stoponerror: raise DMXmlParseError(err, ReturnCodes.E_XML_PARSE_ERROR) if not self.invalidfile: self.__root = self.__tree.getroot() try: check_root_element(self.__root, etree) except ValueError as err: self.invalidfile = True self.fileerror = err if self.stoponerror: raise DMXmlParseError(err, ReturnCodes.E_XML_PARSE_ERROR) if not self.invalidfile: # check for DocBook 5 namespace in start tag try: self.check_docbook5_ns() # check for docmanager element self.__docmanager = self.__tree.find("//dm:docmanager", namespaces=NS) if self.__docmanager is None: log.info("No docmanager element found") self.create_group() else: log.debug("Found docmanager element %s", self.__docmanager.getparent()) except DMNotDocBook5File as err: if self.stoponerror == True: raise DMNotDocBook5File(err.errorstr, err.error)