Refactoring & install with pyproject.toml #1
							
								
								
									
										19
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
<component name="InspectionProjectProfileManager">
 | 
			
		||||
  <profile version="1.0">
 | 
			
		||||
    <option name="myName" value="Project Default" />
 | 
			
		||||
    <inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
 | 
			
		||||
      <option name="ignoredErrors">
 | 
			
		||||
        <list>
 | 
			
		||||
          <option value="E501" />
 | 
			
		||||
        </list>
 | 
			
		||||
      </option>
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="PyShadowingBuiltinsInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
 | 
			
		||||
      <option name="ignoredNames">
 | 
			
		||||
        <list>
 | 
			
		||||
          <option value="format" />
 | 
			
		||||
        </list>
 | 
			
		||||
      </option>
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
  </profile>
 | 
			
		||||
</component>
 | 
			
		||||
							
								
								
									
										5
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							@@ -1,4 +1,7 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (pyuserconfig)" project-jdk-type="Python SDK" />
 | 
			
		||||
  <component name="Black">
 | 
			
		||||
    <option name="sdkName" value="Python 3.12 (userconfig)" />
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (userconfig)" project-jdk-type="Python SDK" />
 | 
			
		||||
</project>
 | 
			
		||||
							
								
								
									
										2
									
								
								.idea/pyuserconfig.iml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								.idea/pyuserconfig.iml
									
									
									
										generated
									
									
									
								
							@@ -2,7 +2,7 @@
 | 
			
		||||
<module type="PYTHON_MODULE" version="4">
 | 
			
		||||
  <component name="NewModuleRootManager">
 | 
			
		||||
    <content url="file://$MODULE_DIR$" />
 | 
			
		||||
    <orderEntry type="jdk" jdkName="Python 3.7 (pyuserconfig)" jdkType="Python SDK" />
 | 
			
		||||
    <orderEntry type="jdk" jdkName="Python 3.12 (userconfig)" jdkType="Python SDK" />
 | 
			
		||||
    <orderEntry type="sourceFolder" forTests="false" />
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="TestRunnerService">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,77 +0,0 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
# encoding: utf-8
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
cfgfile.py
 | 
			
		||||
 | 
			
		||||
Created by Marcus Stoegbauer on 2013-01-12.
 | 
			
		||||
"""
 | 
			
		||||
import configparser
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
class Conf(object):
 | 
			
		||||
    confobj = configparser.RawConfigParser()
 | 
			
		||||
    cfgfile = ''
 | 
			
		||||
    debug = None
 | 
			
		||||
 | 
			
		||||
    def __init__(self, filename=None):
 | 
			
		||||
        """if filename is set, open config file and initialize the ConfigParser
 | 
			
		||||
        """
 | 
			
		||||
        self.confobj = configparser.RawConfigParser()
 | 
			
		||||
        if filename:
 | 
			
		||||
            self.setfilename(filename)
 | 
			
		||||
 | 
			
		||||
    def setdebug(self, debug):
 | 
			
		||||
        """docstring for setdebug"""
 | 
			
		||||
        self.debug = debug
 | 
			
		||||
 | 
			
		||||
    def setfilename(self, filename):
 | 
			
		||||
        """initialize the ConfigParser
 | 
			
		||||
        """
 | 
			
		||||
        ret = self.confobj.read(filename)
 | 
			
		||||
        if len(ret) == 0 or ret[0] != filename:
 | 
			
		||||
            raise Exception('Cannot read config file ' + filename)
 | 
			
		||||
        self.cfgfile = filename
 | 
			
		||||
        if self.debug:
 | 
			
		||||
            self.debug.debug("Read config file %s" % filename, 2)
 | 
			
		||||
            self.debug.debug("Replacing environment variables in %s." % filename, 3)
 | 
			
		||||
 | 
			
		||||
        for s in self.confobj.sections():
 | 
			
		||||
            for (i, val) in self.confobj.items(s):
 | 
			
		||||
                tempre = re.search(r"\$([A-Z]+)[^A-Z]*", val)
 | 
			
		||||
                if tempre:
 | 
			
		||||
                    varname = tempre.group(1)
 | 
			
		||||
                    if self.debug:
 | 
			
		||||
                        self.debug.debug("Found variable %s in %s." % (varname, i), 3)
 | 
			
		||||
                    if varname in os.environ:
 | 
			
		||||
                        if self.debug:
 | 
			
		||||
                            self.debug.debug("%s exists in environment, replacing with %s." %
 | 
			
		||||
                                             (varname, os.environ[varname]), 3)
 | 
			
		||||
                        self.set(s, i, val.replace("$"+varname, os.environ[varname]))
 | 
			
		||||
 | 
			
		||||
    def get(self, section, option):
 | 
			
		||||
        """returns the value of option in section
 | 
			
		||||
        """
 | 
			
		||||
        if not self.cfgfile:
 | 
			
		||||
            raise Exception('No config file set')
 | 
			
		||||
        try:
 | 
			
		||||
            return self.confobj.get(section, option)
 | 
			
		||||
        except configparser.NoOptionError:
 | 
			
		||||
            raise ValueError('Option does not exist')
 | 
			
		||||
 | 
			
		||||
    def set(self, section, option, value):
 | 
			
		||||
        """docstring for update"""
 | 
			
		||||
        self.confobj.set(section, option, value)
 | 
			
		||||
 | 
			
		||||
    def getitems(self, section):
 | 
			
		||||
        """returns all items in section
 | 
			
		||||
        """
 | 
			
		||||
        if not self.cfgfile:
 | 
			
		||||
            raise Exception('No config file set')
 | 
			
		||||
        return self.confobj.items(section)
 | 
			
		||||
 | 
			
		||||
    def check(self, section, option):
 | 
			
		||||
        """checks for option in section"""
 | 
			
		||||
        return self.confobj.has_option(section, option)
 | 
			
		||||
@@ -1,66 +0,0 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
# encoding: utf-8
 | 
			
		||||
#
 | 
			
		||||
"""
 | 
			
		||||
checks.py
 | 
			
		||||
 | 
			
		||||
Created by Marcus Stoegbauer on 2013-01-10.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import platform
 | 
			
		||||
from operator import itemgetter
 | 
			
		||||
 | 
			
		||||
class Checks(object):
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def get_short_hostname(self):
 | 
			
		||||
        """docstring for getShortHostname"""
 | 
			
		||||
        hostname = platform.node()
 | 
			
		||||
        if hostname.count("."):
 | 
			
		||||
            hostname = hostname.split(".")[0]
 | 
			
		||||
        return hostname
 | 
			
		||||
 | 
			
		||||
    # def getShortHostname
 | 
			
		||||
 | 
			
		||||
    def __classes_for_host__(self, reverse=False):
 | 
			
		||||
        """docstring for __classesForHost"""
 | 
			
		||||
        classes = []
 | 
			
		||||
        for c in dir(self):
 | 
			
		||||
            if c.startswith("__"):
 | 
			
		||||
                continue
 | 
			
		||||
            ret = getattr(self, c)()
 | 
			
		||||
            if type(ret) == tuple and len(ret) == 3:
 | 
			
		||||
                classes.append(ret)
 | 
			
		||||
        return map(lambda k: (k[1], k[2]), sorted(classes, key=itemgetter(0), reverse=reverse))
 | 
			
		||||
 | 
			
		||||
    def header(self):
 | 
			
		||||
        """docstring for header"""
 | 
			
		||||
        return (0, "", "header")
 | 
			
		||||
 | 
			
		||||
    def footer(self):
 | 
			
		||||
        """docstring for footer"""
 | 
			
		||||
        return (1000, "", "footer")
 | 
			
		||||
 | 
			
		||||
    def all(self):
 | 
			
		||||
        """docstring for all"""
 | 
			
		||||
        return (998, "", "all")
 | 
			
		||||
 | 
			
		||||
    def arch(self):
 | 
			
		||||
        """docstring for arch"""
 | 
			
		||||
        return (800, "Arch", platform.system())
 | 
			
		||||
 | 
			
		||||
    def hostname(self):
 | 
			
		||||
        """docstring for hostname"""
 | 
			
		||||
        hostname = self.get_short_hostname()
 | 
			
		||||
        return (10, "Host", hostname)
 | 
			
		||||
 | 
			
		||||
    def app(self):
 | 
			
		||||
        """docstring for app"""
 | 
			
		||||
        hostname = self.get_short_hostname()
 | 
			
		||||
        if hostname == "glitters":
 | 
			
		||||
            return (500, "", "rancid_hosts")
 | 
			
		||||
        else:
 | 
			
		||||
            return ()
 | 
			
		||||
    # def app
 | 
			
		||||
# def checks
 | 
			
		||||
							
								
								
									
										171
									
								
								cli/__init__.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										171
									
								
								cli/__init__.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,171 @@
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
import tempfile
 | 
			
		||||
import re
 | 
			
		||||
import argparse
 | 
			
		||||
import time
 | 
			
		||||
from userconfig.cfgfile import Conf
 | 
			
		||||
from userconfig.tools import Debug
 | 
			
		||||
from userconfig.checks import classes_for_host
 | 
			
		||||
#FIXME: fill in: from userconfig.tools import ...
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Usage(Exception):
 | 
			
		||||
    def __init__(self, msg):
 | 
			
		||||
        self.msg = msg
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def workconf(directory, depth=2):
 | 
			
		||||
    """walks through directory, collecting all filenames, returns list of all filenames"""
 | 
			
		||||
    dirs = os.listdir(directory)
 | 
			
		||||
    ret = []
 | 
			
		||||
    debug.stdout("   ================ workconf ===============", 1)
 | 
			
		||||
    debug.stdout("   Finding files in directory %s." % directory, 4)
 | 
			
		||||
    for d in dirs:
 | 
			
		||||
        name = directory+"/"+d
 | 
			
		||||
        if os.path.isdir(name):
 | 
			
		||||
            workconf(name, depth+1)
 | 
			
		||||
        if name.endswith(".swp"):
 | 
			
		||||
            continue
 | 
			
		||||
        if d == ".svn":
 | 
			
		||||
            continue
 | 
			
		||||
        ret.append(name)
 | 
			
		||||
        debug.stdout("   +++ Found file %s in directory %s" % (name, directory), 4)
 | 
			
		||||
    debug.stdout("   ================ workconf ===============", 1)
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def build_file(classfiles, destfile, commentstring):
 | 
			
		||||
    """open all classfiles, assemble them and write the contents into a tempfile
 | 
			
		||||
      returns the name of tempfile
 | 
			
		||||
      :param classfiles:
 | 
			
		||||
      :param destfile:
 | 
			
		||||
      :param commentstring:
 | 
			
		||||
      :return: str
 | 
			
		||||
      """
 | 
			
		||||
    content = []
 | 
			
		||||
    debug.stdout("   ================ build_file ===============", 1)
 | 
			
		||||
    if commentstring != "":
 | 
			
		||||
        debug.stdout("   +++ commentstring found, adding header.", 3)
 | 
			
		||||
        content.append(commentstring + " " + cfg.get("Main","stamp") + " " + time.strftime("%+") + "\n")
 | 
			
		||||
 | 
			
		||||
    for f in classfiles:
 | 
			
		||||
        debug.stdout("   +++ Merging %s." % f, 4)
 | 
			
		||||
        fp = open(f, "r")
 | 
			
		||||
        filecontent = fp.read()
 | 
			
		||||
        fp.close()
 | 
			
		||||
        if commentstring == "":
 | 
			
		||||
            # look for stamp in content, replace with real stamp
 | 
			
		||||
            if re.search(re.escape(cfg.get("Main","stampreplace")), filecontent):
 | 
			
		||||
                debug.stdout("   +++ commentstring empty, replacing stamp in file", 3)
 | 
			
		||||
                filecontent = re.sub(re.escape(cfg.get("Main","stampreplace")), cfg.get("Main","stamp"), filecontent)
 | 
			
		||||
        content.append(filecontent)
 | 
			
		||||
 | 
			
		||||
    (tempfd, tempfilename) = tempfile.mkstemp(prefix=os.path.basename(destfile), dir="/tmp")
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        fp = os.fdopen(tempfd, "w")
 | 
			
		||||
    except:
 | 
			
		||||
        Tools.error("Cannot write to temporary file %s" % tempfilename)
 | 
			
		||||
        os.remove(tempfilename)
 | 
			
		||||
        return False
 | 
			
		||||
    debug.stdout("   +++ Writing merged files into tempfile %s." % tempfilename, 3)
 | 
			
		||||
    for block in content:
 | 
			
		||||
        fp.write(block)
 | 
			
		||||
        fp.write("\n")
 | 
			
		||||
    fp.close()
 | 
			
		||||
    debug.stdout("   ================ build_file ===============", 1)
 | 
			
		||||
    return tempfilename
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def process_all_files(destfiles, dir_config):
 | 
			
		||||
    """processes all files in destfiles, generate files from classes, compare and copy if necessary"""
 | 
			
		||||
    debug.stdout("   ================ process_all_files ===============", 1)
 | 
			
		||||
    for df in destfiles.keys():
 | 
			
		||||
        debug.stdout("   ??? Processing source files for %s." % df, 2)
 | 
			
		||||
        if not os.path.exists(os.path.dirname(df)):
 | 
			
		||||
            debug.stdout("   +++ Directory %s does not exist, creating" % os.path.dirname(df), 1)
 | 
			
		||||
            os.mkdir(os.path.dirname(df))
 | 
			
		||||
        if not os.path.isdir(os.path.dirname(df)):
 | 
			
		||||
            debug.stdout("   --- Destination directory %s does not exist, skipping." % os.path.dirname(df), 1)
 | 
			
		||||
            return False
 | 
			
		||||
        # assemble file to tmp
 | 
			
		||||
        commentstring = ""
 | 
			
		||||
        if dir_config.check("Main", "commentstring"):
 | 
			
		||||
            commentstring = dir_config.get("Main", "commentstring")
 | 
			
		||||
            debug.stdout("   +++ Found commentstring %s in %s" % (commentstring, df), 3)
 | 
			
		||||
 | 
			
		||||
        tempfilename = build_file(destfiles[df], df, commentstring)
 | 
			
		||||
        if not tempfilename:
 | 
			
		||||
            debug.stdout("   --- Error while creating temp file for %s, skipping." % df, 1)
 | 
			
		||||
            continue
 | 
			
		||||
        debug.stdout("   +++ Merged files %s for %s into %s" % (str(destfiles[df]), df, tempfilename), 2)
 | 
			
		||||
 | 
			
		||||
        # diff assembled file and config file
 | 
			
		||||
        if Tools.diff(df, tempfilename, commentstring, debug):
 | 
			
		||||
            debug.stdout("File %s has changed" % df, 0)
 | 
			
		||||
            if not Tools.user_config_generated(df, cfg):
 | 
			
		||||
                debug.stdout("   +++ %s not generated by userconfig, backing up." % df, 2)
 | 
			
		||||
                # file not generated from userconfig -> back up
 | 
			
		||||
                Tools.backup_file(df, debug)
 | 
			
		||||
            # copy tmp file to real location
 | 
			
		||||
            debug.stdout("Copy %s to %s." % (tempfilename, df), 0)
 | 
			
		||||
            Tools.copy_file(tempfilename, df, debug)
 | 
			
		||||
        # remove tmp
 | 
			
		||||
        debug.stdout("   +++ Removing temporary file %s." % tempfilename, 2)
 | 
			
		||||
        os.remove(tempfilename)
 | 
			
		||||
    debug.stdout("   ================ process_all_files ===============", 1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
classchecks = Checks()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    parser = argparse.ArgumentParser(prog='userconfig',
 | 
			
		||||
                                   description='Manages configuration files, usually in the user home directory')
 | 
			
		||||
 | 
			
		||||
    parser.add_argument('-v',
 | 
			
		||||
                      help='Verbosity level (multiple v for higher level)',
 | 
			
		||||
                      dest='verbose', action='count', default=0)
 | 
			
		||||
    parser.add_argument('-f', '--file',
 | 
			
		||||
                      help='userconfig2.cfg config file',
 | 
			
		||||
                      dest='file', action='store')
 | 
			
		||||
    cmdline = parser.parse_args()
 | 
			
		||||
    cfg = Conf(cmdline.file)
 | 
			
		||||
    debug = Debug()
 | 
			
		||||
    cfg.set_debug(debug)
 | 
			
		||||
 | 
			
		||||
    cfg.debug(f"Verbose level is {cfg.debug._verbose}", 1)
 | 
			
		||||
    cfg.debug("================ main ===============", 1)
 | 
			
		||||
    temp_classes = ""
 | 
			
		||||
    for h in classes_for_host():
 | 
			
		||||
        temp_classes=temp_classes + str(h) + ","
 | 
			
		||||
    cfg.debug("+++ Current host is in classes %s" % temp_classes, 1)
 | 
			
		||||
    configdir = cfg.get("configdir")
 | 
			
		||||
    for d in os.listdir(configdir):
 | 
			
		||||
        name = configdir+"/"+d
 | 
			
		||||
        cfg.debug("+++ Working in %s" % name, 1)
 | 
			
		||||
        if not os.path.isdir(name):
 | 
			
		||||
            cfg.debug("--- %s is not a directory, skipping." % name, 3)
 | 
			
		||||
            continue
 | 
			
		||||
        elif d.startswith(".svn") or d.startswith(".git"):
 | 
			
		||||
            cfg.debug("--- %s is .svn or .git, skipping." % name, 3)
 | 
			
		||||
            continue
 | 
			
		||||
        elif os.path.isfile(name+"/.ignore"):
 | 
			
		||||
            cfg.debug("--- %s contains file .ignore, skipping." % name, 3)
 | 
			
		||||
            continue
 | 
			
		||||
        else:
 | 
			
		||||
            cfg.debug("+++ Processing files in %s" % name, 2)
 | 
			
		||||
            (destfiles, dirConfig) = workdir(name)
 | 
			
		||||
            if isinstance(destfiles, dict):
 | 
			
		||||
                if len(destfiles.keys()) > 0:
 | 
			
		||||
                    cfg.debug("+++ Building %d files: %s" % (len(destfiles.keys()), destfiles.keys()), 3)
 | 
			
		||||
                    process_all_files(destfiles, dirConfig)
 | 
			
		||||
            else:
 | 
			
		||||
                cfg.debug("--- No files found for %s, skipping." % name, 1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    main()
 | 
			
		||||
							
								
								
									
										16
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
[build-system]
 | 
			
		||||
requires = ["setuptools", "wheel"]
 | 
			
		||||
build-backend = "setuptools.build_meta"
 | 
			
		||||
 | 
			
		||||
[project]
 | 
			
		||||
name = "userconfig"
 | 
			
		||||
version = "2.0b-1"
 | 
			
		||||
authors = [ {name = "Marcus Stoegbauer", email = "marcus@grmpf.org"} ]
 | 
			
		||||
maintainers = [ {name = "Marcus Stoegbauer", email = "marcus@grmpf.org"} ]
 | 
			
		||||
description = "Generate config files for user home"
 | 
			
		||||
 | 
			
		||||
[project.scripts]
 | 
			
		||||
userconfig = "cli:main"
 | 
			
		||||
 | 
			
		||||
[tool.setuptools]
 | 
			
		||||
packages = [ "userconfig", "cli" ]
 | 
			
		||||
							
								
								
									
										16
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								setup.py
									
									
									
									
									
								
							@@ -1,13 +1,5 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
# migrated to pyproject.toml
 | 
			
		||||
# as reccomended: https://packaging.python.org/en/latest/guides/modernize-setup-py-project/#what-if-something-that-can-not-be-changed-expects-a-setup-py-file
 | 
			
		||||
from setuptools import setup
 | 
			
		||||
 | 
			
		||||
from distutils.core import setup
 | 
			
		||||
 | 
			
		||||
setup(name="userconfig",
 | 
			
		||||
      version="0.1",
 | 
			
		||||
      description="Generate config files for user home",
 | 
			
		||||
      author="Marcus Stoegbauer",
 | 
			
		||||
      author_email="marcus@grmpf.org",
 | 
			
		||||
      packages=["Userconfig"],
 | 
			
		||||
      scripts=["userconfig.py"],
 | 
			
		||||
      data_files=[('etc', ['userconfig.cfg'])]
 | 
			
		||||
      )
 | 
			
		||||
setup()
 | 
			
		||||
							
								
								
									
										270
									
								
								userconfig.py
									
									
									
									
									
								
							
							
						
						
									
										270
									
								
								userconfig.py
									
									
									
									
									
								
							@@ -1,270 +0,0 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
# encoding: utf-8
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
userconfig.py
 | 
			
		||||
 | 
			
		||||
Created by Marcus Stoegbauer on 2013-01-10.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
import tempfile
 | 
			
		||||
import re
 | 
			
		||||
import getopt
 | 
			
		||||
import time
 | 
			
		||||
import subprocess
 | 
			
		||||
 | 
			
		||||
# 
 | 
			
		||||
import Userconfig.cfgfile as cfgfile
 | 
			
		||||
from Userconfig.checks import Checks
 | 
			
		||||
import Userconfig.Tools as Tools
 | 
			
		||||
 | 
			
		||||
debug = Tools.Debug()
 | 
			
		||||
 | 
			
		||||
classchecks = Checks()
 | 
			
		||||
cfg = cfgfile.Conf()
 | 
			
		||||
 | 
			
		||||
help_message = """
 | 
			
		||||
-h help
 | 
			
		||||
-v verbose level (multiple v for higher level)
 | 
			
		||||
-c userconfig.cfg config file
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Usage(Exception):
 | 
			
		||||
    def __init__(self, msg):
 | 
			
		||||
        self.msg = msg
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def workconf(directory, depth=2):
 | 
			
		||||
    """walks through directory, collecting all filenames, returns list of all filenames"""
 | 
			
		||||
    dirs = os.listdir(directory)
 | 
			
		||||
    ret = []
 | 
			
		||||
    debug.debug("   ================ workconf ===============", 1)
 | 
			
		||||
    debug.debug("   Finding files in directory %s." % directory, 4)
 | 
			
		||||
    for d in dirs:
 | 
			
		||||
        name = directory+"/"+d
 | 
			
		||||
        if os.path.isdir(name):
 | 
			
		||||
            workconf(name, depth+1)
 | 
			
		||||
        if name.endswith(".swp"):
 | 
			
		||||
            continue
 | 
			
		||||
        if d == ".svn":
 | 
			
		||||
            continue
 | 
			
		||||
        ret.append(name)
 | 
			
		||||
        debug.debug("   +++ Found file %s in directory %s" % (name, directory), 4)
 | 
			
		||||
    debug.debug("   ================ workconf ===============", 1)
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def workdir(directory):
 | 
			
		||||
    """walks through all host classes, checking if the classes directory exists in directory
 | 
			
		||||
       then collect all filenames within this directory and return a dict of all files for this
 | 
			
		||||
       directory
 | 
			
		||||
    """
 | 
			
		||||
    debug.debug("   ================ workdir ===============", 1)
 | 
			
		||||
    debug.debug("   Working on directory %s" % directory, 3)
 | 
			
		||||
    # skip directory if no CONFIGFILE present
 | 
			
		||||
    if not os.path.isfile(directory+"/"+cfg.get("Main", "configfile")):
 | 
			
		||||
        debug.debug("   --- No %s in %s, skipping." % (cfg.get("Main", "configfile"), directory), 1)
 | 
			
		||||
        return {},None
 | 
			
		||||
 | 
			
		||||
    # get config file for directory
 | 
			
		||||
    dir_config = Tools.get_config(directory + "/" + cfg.get("Main", "configfile"))
 | 
			
		||||
    if not dir_config:
 | 
			
		||||
        debug.debug("   --- Cannot read %s in %s, skipping." % (cfg.get("Main", "configfile"), directory), 1)
 | 
			
		||||
        return {},None
 | 
			
		||||
 | 
			
		||||
    destdir = dir_config.get("Main","dest")
 | 
			
		||||
    # destfiles is a dict of all files that will be created from the classes config
 | 
			
		||||
    # key is the destination filename, values are all classes filenames that are used to
 | 
			
		||||
    # build the file
 | 
			
		||||
    destfiles = {}
 | 
			
		||||
    # FIXME: reverse_order should really be a bool in .cfg, implement variable types in cfg file
 | 
			
		||||
    reverse_sort = False
 | 
			
		||||
    try:
 | 
			
		||||
        reverse_sort = (dir_config.get("Main", "reverse") == 'True')
 | 
			
		||||
    except ValueError:
 | 
			
		||||
        reverse_sort = False
 | 
			
		||||
 | 
			
		||||
    if os.access(directory + "/install.sh", os.X_OK):
 | 
			
		||||
        subprocess.call([directory + "/install.sh"])
 | 
			
		||||
 | 
			
		||||
    # walk through all know classes in directory and find filenames
 | 
			
		||||
    for h in classchecks.__classes_for_host__(reverse_sort):
 | 
			
		||||
        # build classes directory
 | 
			
		||||
        if h[0] != "":
 | 
			
		||||
            classdir = directory+"/"+h[0]+"_"+h[1]
 | 
			
		||||
        else:
 | 
			
		||||
            classdir = directory+"/"+h[1]
 | 
			
		||||
        debug.debug("   ??? Looking for directory %s." % classdir, 4)
 | 
			
		||||
        # if class directory exists
 | 
			
		||||
        if os.path.isdir(classdir):
 | 
			
		||||
            debug.debug("   +++ Found directory %s, getting files." % classdir, 4)
 | 
			
		||||
            # get list of files within this class directory
 | 
			
		||||
            tempfiles = workconf(classdir)
 | 
			
		||||
            debug.debug("   +++ Got %d files: %s." % (len(tempfiles), str(tempfiles)), 4)
 | 
			
		||||
            # put files into dict
 | 
			
		||||
            for f in tempfiles:
 | 
			
		||||
                destname = destdir+os.path.basename(f)  # destination filename
 | 
			
		||||
                if not destname in destfiles:
 | 
			
		||||
                    destfiles[destname] = []
 | 
			
		||||
                destfiles[destname].append(f) # append each file to dict
 | 
			
		||||
                debug.debug("   +++ Added file to %s, now %d files: %s" % (destname, len(destfiles[destname]), destfiles[destname]), 4)
 | 
			
		||||
 | 
			
		||||
    debug.debug("   === workdir: %s, Files: %s" % (directory, str(destfiles)), 3)
 | 
			
		||||
    debug.debug("   ================ workdir ===============", 1)
 | 
			
		||||
    return destfiles, dir_config
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def build_file(classfiles, destfile, commentstring):
 | 
			
		||||
    """open all classfiles, assemble them and write the contents into a tempfile
 | 
			
		||||
      returns the name of tempfile
 | 
			
		||||
      :param classfiles:
 | 
			
		||||
      :param destfile:
 | 
			
		||||
      :param commentstring:
 | 
			
		||||
      :return: str
 | 
			
		||||
      """
 | 
			
		||||
    content = []
 | 
			
		||||
    debug.debug("   ================ build_file ===============", 1)
 | 
			
		||||
    if commentstring != "":
 | 
			
		||||
        debug.debug("   +++ commentstring found, adding header.", 3)
 | 
			
		||||
        content.append(commentstring + " " + cfg.get("Main","stamp") + " " + time.strftime("%+") + "\n")
 | 
			
		||||
 | 
			
		||||
    for f in classfiles:
 | 
			
		||||
        debug.debug("   +++ Merging %s." % f, 4)
 | 
			
		||||
        fp = open(f, "r")
 | 
			
		||||
        filecontent = fp.read()
 | 
			
		||||
        fp.close()
 | 
			
		||||
        if commentstring == "":
 | 
			
		||||
            # look for stamp in content, replace with real stamp
 | 
			
		||||
            if re.search(re.escape(cfg.get("Main","stampreplace")), filecontent):
 | 
			
		||||
                debug.debug("   +++ commentstring empty, replacing stamp in file", 3)
 | 
			
		||||
                filecontent = re.sub(re.escape(cfg.get("Main","stampreplace")), cfg.get("Main","stamp"), filecontent)
 | 
			
		||||
        content.append(filecontent)
 | 
			
		||||
 | 
			
		||||
    (tempfd, tempfilename) = tempfile.mkstemp(prefix=os.path.basename(destfile), dir="/tmp")
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        fp = os.fdopen(tempfd, "w")
 | 
			
		||||
    except:
 | 
			
		||||
        Tools.error("Cannot write to temporary file %s" % tempfilename)
 | 
			
		||||
        os.remove(tempfilename)
 | 
			
		||||
        return False
 | 
			
		||||
    debug.debug("   +++ Writing merged files into tempfile %s." % tempfilename, 3)
 | 
			
		||||
    for block in content:
 | 
			
		||||
        fp.write(block)
 | 
			
		||||
        fp.write("\n")
 | 
			
		||||
    fp.close()
 | 
			
		||||
    debug.debug("   ================ build_file ===============", 1)
 | 
			
		||||
    return tempfilename
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def process_all_files(destfiles, dir_config):
 | 
			
		||||
    """processes all files in destfiles, generate files from classes, compare and copy if necessary"""
 | 
			
		||||
    debug.debug("   ================ process_all_files ===============", 1)
 | 
			
		||||
    for df in destfiles.keys():
 | 
			
		||||
        debug.debug("   ??? Processing source files for %s." % df, 2)
 | 
			
		||||
        if not os.path.exists(os.path.dirname(df)):
 | 
			
		||||
            debug.debug("   +++ Directory %s does not exist, creating" % os.path.dirname(df), 1)
 | 
			
		||||
            os.mkdir(os.path.dirname(df))
 | 
			
		||||
        if not os.path.isdir(os.path.dirname(df)):
 | 
			
		||||
            debug.debug("   --- Destination directory %s does not exist, skipping." % os.path.dirname(df), 1)
 | 
			
		||||
            return False
 | 
			
		||||
        # assemble file to tmp
 | 
			
		||||
        commentstring = ""
 | 
			
		||||
        if dir_config.check("Main", "commentstring"):
 | 
			
		||||
            commentstring = dir_config.get("Main", "commentstring")
 | 
			
		||||
            debug.debug("   +++ Found commentstring %s in %s" % (commentstring, df), 3)
 | 
			
		||||
 | 
			
		||||
        tempfilename = build_file(destfiles[df], df, commentstring)
 | 
			
		||||
        if not tempfilename:
 | 
			
		||||
            debug.debug("   --- Error while creating temp file for %s, skipping." % df, 1)
 | 
			
		||||
            continue
 | 
			
		||||
        debug.debug("   +++ Merged files %s for %s into %s" % (str(destfiles[df]), df, tempfilename), 2)
 | 
			
		||||
 | 
			
		||||
        # diff assembled file and config file
 | 
			
		||||
        if Tools.diff(df, tempfilename, commentstring, debug):
 | 
			
		||||
            debug.debug("File %s has changed" % df, 0)
 | 
			
		||||
            if not Tools.user_config_generated(df, cfg):
 | 
			
		||||
                debug.debug("   +++ %s not generated by userconfig, backing up." % df, 2)
 | 
			
		||||
                # file not generated from userconfig -> back up
 | 
			
		||||
                Tools.backup_file(df, debug)
 | 
			
		||||
            # copy tmp file to real location
 | 
			
		||||
            debug.debug("Copy %s to %s." % (tempfilename, df), 0)
 | 
			
		||||
            Tools.copy_file(tempfilename, df, debug)
 | 
			
		||||
        # remove tmp
 | 
			
		||||
        debug.debug("   +++ Removing temporary file %s." % tempfilename, 2)
 | 
			
		||||
        os.remove(tempfilename)
 | 
			
		||||
    debug.debug("   ================ process_all_files ===============", 1)
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    configfile_destinations = [os.environ['HOME'] + "/etc/", 
 | 
			
		||||
                               os.environ['HOME'] + "/.local/etc"]
 | 
			
		||||
    configfile = ''
 | 
			
		||||
    for directory in configfile_destinations:
 | 
			
		||||
        if os.path.isfile(directory + "/userconfig.cfg"):
 | 
			
		||||
            configfile = directory + "/userconfig.cfg"
 | 
			
		||||
            break
 | 
			
		||||
    try:
 | 
			
		||||
        try:
 | 
			
		||||
            opts, args = getopt.getopt(sys.argv[1:], "hdc:v", ["help", "debug", "config="])
 | 
			
		||||
        except getopt.GetoptError as msg:
 | 
			
		||||
            raise Usage(msg)
 | 
			
		||||
 | 
			
		||||
        for option, value in opts:
 | 
			
		||||
            if option == "-v":
 | 
			
		||||
                debug.addverbose()
 | 
			
		||||
            if option in ("-h", "--help"):
 | 
			
		||||
                raise Usage(help_message)
 | 
			
		||||
            if option in ("-d", "--debug.debug"):
 | 
			
		||||
                pass
 | 
			
		||||
            if option in ("-c", "--config"):
 | 
			
		||||
                configfile = value
 | 
			
		||||
    except Usage as err:
 | 
			
		||||
        Tools.error(sys.argv[0].split("/")[-1] + ": " + str(err.msg))
 | 
			
		||||
        Tools.error("\t for help use --help")
 | 
			
		||||
        return 2
 | 
			
		||||
 | 
			
		||||
    debug.debug("Verbose level is %d" % debug.verbose, 1)
 | 
			
		||||
    debug.debug("Using configfile %s." % configfile, 1)
 | 
			
		||||
    if not os.path.isfile(configfile):
 | 
			
		||||
        Tools.error("No config file specified.")
 | 
			
		||||
        return 2
 | 
			
		||||
 | 
			
		||||
    cfg.setdebug(debug)
 | 
			
		||||
    cfg.setfilename(configfile)
 | 
			
		||||
 | 
			
		||||
    debug.debug("================ main ===============", 1)
 | 
			
		||||
    tempclasses = ""
 | 
			
		||||
    for h in classchecks.__classes_for_host__():
 | 
			
		||||
        tempclasses=tempclasses + str(h) + ","
 | 
			
		||||
    debug.debug("+++ Current host is in classes %s" % tempclasses, 1)
 | 
			
		||||
    configdir = cfg.get("Main", "configdir")
 | 
			
		||||
    for d in os.listdir(configdir):
 | 
			
		||||
        destfiles = {}
 | 
			
		||||
        name = configdir+"/"+d
 | 
			
		||||
        debug.debug("+++ Working in %s" % name, 1)
 | 
			
		||||
        if not os.path.isdir(name):
 | 
			
		||||
            debug.debug("--- %s is not a directory, skipping." % name, 3)
 | 
			
		||||
            continue
 | 
			
		||||
        elif d.startswith(".svn") or d.startswith(".git"):
 | 
			
		||||
            debug.debug("--- %s is .svn or .git, skipping." % name, 3)
 | 
			
		||||
            continue
 | 
			
		||||
        elif os.path.isfile(name+"/.ignore"):
 | 
			
		||||
            debug.debug("--- %s contains file .ignore, skipping." % name, 3)
 | 
			
		||||
            continue
 | 
			
		||||
        else:
 | 
			
		||||
            debug.debug("+++ Processing files in %s" % name, 2)
 | 
			
		||||
            (destfiles, dirConfig) = workdir(name)
 | 
			
		||||
            if isinstance(destfiles, dict):
 | 
			
		||||
                if len(destfiles.keys()) > 0:
 | 
			
		||||
                    debug.debug("+++ Building %d files: %s" % (len(destfiles.keys()), destfiles.keys()), 3)
 | 
			
		||||
                    process_all_files(destfiles, dirConfig)
 | 
			
		||||
            else:
 | 
			
		||||
                debug.debug("--- No files found for %s, skipping." % name, 1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    main()
 | 
			
		||||
							
								
								
									
										67
									
								
								userconfig/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								userconfig/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
from userconfig.tools import get_config
 | 
			
		||||
import subprocess
 | 
			
		||||
from userconfig.checks import classes_for_host
 | 
			
		||||
 | 
			
		||||
class Userconfig():
 | 
			
		||||
    _cfg = None
 | 
			
		||||
 | 
			
		||||
    def __init__(self, cfg):
 | 
			
		||||
        self._cfg = cfg
 | 
			
		||||
 | 
			
		||||
    def workdir(self, directory):
 | 
			
		||||
        """walks through all host classes, checking if the classes directory exists in directory
 | 
			
		||||
           then collect all filenames within this directory and return a dict of all files for this
 | 
			
		||||
           directory
 | 
			
		||||
        """
 | 
			
		||||
        self._cfg.debug.stdout("   ================ workdir ===============", 1)
 | 
			
		||||
        self._cfg.debug.stdout("   Working on directory %s" % directory, 3)
 | 
			
		||||
        # skip directory if no CONFIGFILE present
 | 
			
		||||
        if not os.path.isfile(directory+"/"+self._cfg.get("configfile")):
 | 
			
		||||
            self._cfg.debug.stdout(f'   --- No file {self._cfg.get("configfile")} in {directory}, skipping.', 1)
 | 
			
		||||
            return {}, None
 | 
			
		||||
 | 
			
		||||
        # get config file for directory
 | 
			
		||||
        dir_config = get_config(directory + "/" + cfg.get("configfile"))
 | 
			
		||||
        if not dir_config:
 | 
			
		||||
            self._cfg.debug.stdout(f'   --- Cannot read config file {self._cfg.get("configfile")} in {directory}, skipping.', 1)
 | 
			
		||||
            return {}, None
 | 
			
		||||
 | 
			
		||||
        destdir = dir_config.get(section="Main",option="dest")
 | 
			
		||||
        # destfiles is a dict of all files that will be created from the classes config
 | 
			
		||||
        # key is the destination filename, values are all classes filenames that are used to
 | 
			
		||||
        # build the file
 | 
			
		||||
        destfiles = {}
 | 
			
		||||
        reverse_sort = False
 | 
			
		||||
        try:
 | 
			
		||||
            reverse_sort = dir_config.get(section="Main", option="reverse", boolean=True)
 | 
			
		||||
        except ValueError:
 | 
			
		||||
            reverse_sort = False
 | 
			
		||||
 | 
			
		||||
        if os.access(directory + "/install.sh", os.X_OK):
 | 
			
		||||
            subprocess.call([directory + "/install.sh"])
 | 
			
		||||
 | 
			
		||||
        # walk through all know classes in directory and find filenames
 | 
			
		||||
        for h in classes_for_host(reverse_sort): #### continue here
 | 
			
		||||
            # build classes directory
 | 
			
		||||
            if h[0] != "":
 | 
			
		||||
                classdir = directory+"/"+h[0]+"_"+h[1]
 | 
			
		||||
            else:
 | 
			
		||||
                classdir = directory+"/"+h[1]
 | 
			
		||||
            debug.stdout("   ??? Looking for directory %s." % classdir, 4)
 | 
			
		||||
            # if class directory exists
 | 
			
		||||
            if os.path.isdir(classdir):
 | 
			
		||||
                debug.stdout("   +++ Found directory %s, getting files." % classdir, 4)
 | 
			
		||||
                # get list of files within this class directory
 | 
			
		||||
                tempfiles = workconf(classdir)
 | 
			
		||||
                debug.stdout("   +++ Got %d files: %s." % (len(tempfiles), str(tempfiles)), 4)
 | 
			
		||||
                # put files into dict
 | 
			
		||||
                for f in tempfiles:
 | 
			
		||||
                    destname = destdir+os.path.basename(f)  # destination filename
 | 
			
		||||
                    if not destname in destfiles:
 | 
			
		||||
                        destfiles[destname] = []
 | 
			
		||||
                    destfiles[destname].append(f) # append each file to dict
 | 
			
		||||
                    debug.stdout("   +++ Added file to %s, now %d files: %s" % (destname, len(destfiles[destname]), destfiles[destname]), 4)
 | 
			
		||||
 | 
			
		||||
        debug.stdout("   === workdir: %s, Files: %s" % (directory, str(destfiles)), 3)
 | 
			
		||||
        debug.stdout("   ================ workdir ===============", 1)
 | 
			
		||||
        return destfiles, dir_config
 | 
			
		||||
							
								
								
									
										57
									
								
								userconfig/cfgfile.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								userconfig/cfgfile.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
import configparser
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Conf(object):
 | 
			
		||||
    _confobj = configparser.ConfigParser(os.environ)
 | 
			
		||||
    _cfgfiles = []
 | 
			
		||||
    debug = None
 | 
			
		||||
 | 
			
		||||
    def __init__(self, filename=None, debug=None):
 | 
			
		||||
        if debug:
 | 
			
		||||
            self.set_debug(debug)
 | 
			
		||||
        filenames = []
 | 
			
		||||
        if filename:
 | 
			
		||||
            filenames.append(filename)
 | 
			
		||||
        filenames.append(f'{os.environ.get("HOME")}/etc/userconfig2.conf')
 | 
			
		||||
        ret = self.set_filenames(filenames)
 | 
			
		||||
        if not ret:
 | 
			
		||||
            raise ValueError(f'Cannot open either configuration file: {",".join(filenames)}')
 | 
			
		||||
 | 
			
		||||
    def set_debug(self, debug):
 | 
			
		||||
        self.debug = debug
 | 
			
		||||
 | 
			
		||||
    def set_filenames(self, filenames):
 | 
			
		||||
        ret = self._confobj.read(filenames)
 | 
			
		||||
        if len(ret) == 0:
 | 
			
		||||
            return None
 | 
			
		||||
        if self.debug:
 | 
			
		||||
            self.debug.stdout("Read config files: %s" % ", ".join(filenames), 2)
 | 
			
		||||
        return ret
 | 
			
		||||
 | 
			
		||||
    def get(self, option, boolean=False, section='userconfig'):
 | 
			
		||||
        try:
 | 
			
		||||
            if boolean:
 | 
			
		||||
                return self._confobj.getboolean(section, option)
 | 
			
		||||
            else:
 | 
			
		||||
                return self._confobj.get(section, option)
 | 
			
		||||
        except (configparser.NoOptionError, configparser.NoOptionError) as e:
 | 
			
		||||
            raise ValueError(f'Option {option} does not exist in section {section}: {e}')
 | 
			
		||||
 | 
			
		||||
    def set(self, option, value, section='userconfig'):
 | 
			
		||||
        try:
 | 
			
		||||
            self._confobj.set(section, option, value)
 | 
			
		||||
        except configparser.NoSectionError as e:
 | 
			
		||||
            raise ValueError(f'Section {section} does not exist: {e}')
 | 
			
		||||
 | 
			
		||||
    def get_items(self, section='userconfig'):
 | 
			
		||||
        try:
 | 
			
		||||
            return self._confobj.items(section)
 | 
			
		||||
        except configparser.NoSectionError as e:
 | 
			
		||||
            raise ValueError(f'Section {section} does not exist: {e}')
 | 
			
		||||
 | 
			
		||||
    def check(self, option, section='userconfig'):
 | 
			
		||||
        return self._confobj.has_option(section, option)
 | 
			
		||||
 | 
			
		||||
    def sections(self):
 | 
			
		||||
        return self._confobj.sections()
 | 
			
		||||
							
								
								
									
										19
									
								
								userconfig/checks.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								userconfig/checks.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
import platform
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_short_hostname():
 | 
			
		||||
    hostname = platform.node()
 | 
			
		||||
    if hostname.count("."):
 | 
			
		||||
        hostname = hostname.split(".")[0]
 | 
			
		||||
    return hostname
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def classes_for_host(reverse=False):
 | 
			
		||||
    classes = [(0, "", "header"),
 | 
			
		||||
               (1000, "", "footer"),
 | 
			
		||||
               (998, "", "all"),
 | 
			
		||||
               (800, "Arch", platform.system()),
 | 
			
		||||
               (10, "Host", get_short_hostname())
 | 
			
		||||
               ]
 | 
			
		||||
    classes.sort(key=lambda k: k[0], reverse=reverse)
 | 
			
		||||
    return [(k[1], k[2]) for k in classes]
 | 
			
		||||
@@ -1,67 +1,47 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
# encoding: utf-8
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
Tools.py
 | 
			
		||||
 | 
			
		||||
Created by Marcus Stoegbauer on 2013-01-12.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
import Userconfig.cfgfile as cfgfile
 | 
			
		||||
from userconfig.cfgfile import Conf
 | 
			
		||||
import re
 | 
			
		||||
import time
 | 
			
		||||
import shutil
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Debug(object):
 | 
			
		||||
    verbose = 0
 | 
			
		||||
class Debug():
 | 
			
		||||
    _verbose = 0
 | 
			
		||||
 | 
			
		||||
    def __init__(self, verbose=0):
 | 
			
		||||
        self.setverbose(verbose)
 | 
			
		||||
        self.set_verbose(verbose)
 | 
			
		||||
 | 
			
		||||
    def setverbose(self, verbose):
 | 
			
		||||
        """docstring for setverbose"""
 | 
			
		||||
        self.verbose = verbose
 | 
			
		||||
    def set_verbose(self, verbose):
 | 
			
		||||
        self._verbose = verbose
 | 
			
		||||
 | 
			
		||||
    def addverbose(self):
 | 
			
		||||
        """docstring for setverbose"""
 | 
			
		||||
        self.verbose += 1
 | 
			
		||||
    def add_verbose(self):
 | 
			
		||||
        self._verbose += 1
 | 
			
		||||
 | 
			
		||||
    def debug(self, out, level=0):
 | 
			
		||||
        """docstring for debug"""
 | 
			
		||||
        if self.verbose >= level:
 | 
			
		||||
    def stdout(self, out, level=0):
 | 
			
		||||
        if self._verbose >= level:
 | 
			
		||||
            print(out)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def error(out):
 | 
			
		||||
    """Print error on stderr"""
 | 
			
		||||
    print(str(out)+"\n", file=sys.stderr)
 | 
			
		||||
    def stderr(self, out, level=0):
 | 
			
		||||
        if self._verbose >= level:
 | 
			
		||||
            print(str(out)+"\n", file=sys.stderr)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_config(filename):
 | 
			
		||||
def get_config(filename, cfg):
 | 
			
		||||
    """reads filename as config, checks for DEST parameter and returns cfgfile object"""
 | 
			
		||||
    ret = None
 | 
			
		||||
    try:
 | 
			
		||||
        ret = cfgfile.Conf(filename)
 | 
			
		||||
        ret = Conf(filename)
 | 
			
		||||
    except:
 | 
			
		||||
        error("Error reading config file %s" % filename)
 | 
			
		||||
        cfg.debug.stderr("Error reading config file %s" % filename)
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    # check for DEST parameter
 | 
			
		||||
    if not ret.check("Main", "dest"):
 | 
			
		||||
        error("No DEST in config file %s" % filename)
 | 
			
		||||
        cfg.debug.stderr("No dest in config file %s" % filename)
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    # replace $HOME with real home directory
 | 
			
		||||
    if ret.get("Main", "dest") == "$HOME":
 | 
			
		||||
        ret.set("Main", "dest", os.environ['HOME'])
 | 
			
		||||
 | 
			
		||||
    # make sure DEST ends with /
 | 
			
		||||
    if not ret.get("Main", "dest").endswith("/"):
 | 
			
		||||
        ret.set("Main", "dest", ret.get("Main", "dest")+"/")
 | 
			
		||||
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -76,9 +56,9 @@ def read_skip_comment(fp, commentstring):
 | 
			
		||||
 | 
			
		||||
def diff(destfile, tempfile, commentstring, debug):
 | 
			
		||||
    """diff destfile and tempfile, returns True if files differ, False if they are the same"""
 | 
			
		||||
    debug.debug("Diffing %s and %s" % (destfile, tempfile), 3)
 | 
			
		||||
    debug.stdout("Diffing %s and %s" % (destfile, tempfile), 3)
 | 
			
		||||
    if not os.path.isfile(destfile):
 | 
			
		||||
        debug.debug("Destfile %s does not exist, returning True." % destfile, 3)
 | 
			
		||||
        debug.stdout("Destfile %s does not exist, returning True." % destfile, 3)
 | 
			
		||||
        # destfile does not exist -> copy tempfile over
 | 
			
		||||
        return True
 | 
			
		||||
    # if not destfile
 | 
			
		||||
@@ -95,13 +75,13 @@ def diff(destfile, tempfile, commentstring, debug):
 | 
			
		||||
        if line1 != line2:
 | 
			
		||||
            fp1.close()
 | 
			
		||||
            fp2.close()
 | 
			
		||||
            debug.debug("%s differs, return true" % destfile, 3)
 | 
			
		||||
            debug.stdout("%s differs, return true" % destfile, 3)
 | 
			
		||||
            return True
 | 
			
		||||
        # if differ
 | 
			
		||||
    # for line
 | 
			
		||||
    fp1.close()
 | 
			
		||||
    fp2.close()
 | 
			
		||||
    debug.debug("%s is the same, return false" % destfile, 3)
 | 
			
		||||
    debug.stdout("%s is the same, return false" % destfile, 3)
 | 
			
		||||
    return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -127,18 +107,18 @@ def user_config_generated(filename, cfg):
 | 
			
		||||
def backup_file(filename, debug):
 | 
			
		||||
    """make backup of filename, returns True if backup is successful, False else"""
 | 
			
		||||
    if os.path.isfile(filename):
 | 
			
		||||
        debug.debug("%s exists, finding backup name." % filename, 3)
 | 
			
		||||
        debug.stdout("%s exists, finding backup name." % filename, 3)
 | 
			
		||||
        backupname = filename+".userconfig."+time.strftime("%F")
 | 
			
		||||
        testbackupname = backupname
 | 
			
		||||
        counter = 0
 | 
			
		||||
        while os.path.isfile(testbackupname):
 | 
			
		||||
            counter+=1
 | 
			
		||||
            testbackupname=backupname+"."+str(counter)
 | 
			
		||||
        debug.debug("Renaming %s to %s" % (filename, testbackupname), 1)
 | 
			
		||||
        debug.stdout("Renaming %s to %s" % (filename, testbackupname), 1)
 | 
			
		||||
        os.rename(filename, testbackupname)
 | 
			
		||||
        return True
 | 
			
		||||
    else:
 | 
			
		||||
        debug.debug("%s does not exist, do not need backup." % filename, 3)
 | 
			
		||||
        debug.stdout("%s does not exist, do not need backup." % filename, 3)
 | 
			
		||||
    return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -147,12 +127,12 @@ def copy_file(sourcefile, destfile, debug):
 | 
			
		||||
 | 
			
		||||
    if os.path.isfile(sourcefile):
 | 
			
		||||
        # sourcefile exists
 | 
			
		||||
        debug.debug("Source file %s exists, proceeding with copy." % sourcefile, 3)
 | 
			
		||||
        debug.stdout("Source file %s exists, proceeding with copy." % sourcefile, 3)
 | 
			
		||||
        if not os.path.isfile(destfile) or os.access(destfile, os.W_OK):
 | 
			
		||||
            debug.debug("Copying %s to %s" % (sourcefile, destfile), 1)
 | 
			
		||||
            debug.stdout("Copying %s to %s" % (sourcefile, destfile), 1)
 | 
			
		||||
            shutil.copy(sourcefile, destfile)
 | 
			
		||||
            return True
 | 
			
		||||
            # destfile is writable
 | 
			
		||||
        else:
 | 
			
		||||
            debug.debug("Destination file %s does not exist or is not writable." % destfile, 3)
 | 
			
		||||
            debug.stdout("Destination file %s does not exist or is not writable." % destfile, 3)
 | 
			
		||||
    return False
 | 
			
		||||
		Reference in New Issue
	
	Block a user