Merge pull request 'Refactoring & install with pyproject.toml' (#1) from toml into main
Reviewed-on: #1
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -4,3 +4,4 @@ build/
 | 
				
			|||||||
.idea/
 | 
					.idea/
 | 
				
			||||||
.venv
 | 
					.venv
 | 
				
			||||||
userconfig.egg-info/
 | 
					userconfig.egg-info/
 | 
				
			||||||
 | 
					*.swp
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										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"?>
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
<project version="4">
 | 
					<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.6 (pyuserconfig)" />
 | 
				
			||||||
 | 
					  </component>
 | 
				
			||||||
 | 
					  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (userconfig)" project-jdk-type="Python SDK" />
 | 
				
			||||||
</project>
 | 
					</project>
 | 
				
			||||||
							
								
								
									
										6
									
								
								.idea/pyuserconfig.iml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								.idea/pyuserconfig.iml
									
									
									
										generated
									
									
									
								
							@@ -1,8 +1,10 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
<module type="PYTHON_MODULE" version="4">
 | 
					<module type="PYTHON_MODULE" version="4">
 | 
				
			||||||
  <component name="NewModuleRootManager">
 | 
					  <component name="NewModuleRootManager">
 | 
				
			||||||
    <content url="file://$MODULE_DIR$" />
 | 
					    <content url="file://$MODULE_DIR$">
 | 
				
			||||||
    <orderEntry type="jdk" jdkName="Python 3.7 (pyuserconfig)" jdkType="Python SDK" />
 | 
					      <excludeFolder url="file://$MODULE_DIR$/venv" />
 | 
				
			||||||
 | 
					    </content>
 | 
				
			||||||
 | 
					    <orderEntry type="inheritedJdk" />
 | 
				
			||||||
    <orderEntry type="sourceFolder" forTests="false" />
 | 
					    <orderEntry type="sourceFolder" forTests="false" />
 | 
				
			||||||
  </component>
 | 
					  </component>
 | 
				
			||||||
  <component name="TestRunnerService">
 | 
					  <component name="TestRunnerService">
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										40
									
								
								.idea/shelf/Uncommitted_changes_before_Checkout_at_29_03_2024_21_55_[Changes]/shelved.patch
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								.idea/shelf/Uncommitted_changes_before_Checkout_at_29_03_2024_21_55_[Changes]/shelved.patch
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					Index: .idea/pyuserconfig.iml
 | 
				
			||||||
 | 
					IDEA additional info:
 | 
				
			||||||
 | 
					Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
 | 
				
			||||||
 | 
					<+><?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"PYTHON_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\">\n    <content url=\"file://$MODULE_DIR$\" />\n    <orderEntry type=\"jdk\" jdkName=\"Python 3.7 (pyuserconfig)\" jdkType=\"Python SDK\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n  <component name=\"TestRunnerService\">\n    <option name=\"PROJECT_TEST_RUNNER\" value=\"Unittests\" />\n  </component>\n</module>
 | 
				
			||||||
 | 
					Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
 | 
				
			||||||
 | 
					<+>UTF-8
 | 
				
			||||||
 | 
					===================================================================
 | 
				
			||||||
 | 
					diff --git a/.idea/pyuserconfig.iml b/.idea/pyuserconfig.iml
 | 
				
			||||||
 | 
					--- a/.idea/pyuserconfig.iml	(revision cba08629cbfd9427213cb8e1719d2ce1e601bdfc)
 | 
				
			||||||
 | 
					+++ b/.idea/pyuserconfig.iml	(date 1711709021136)
 | 
				
			||||||
 | 
					@@ -1,8 +1,10 @@
 | 
				
			||||||
 | 
					 <?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					 <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" />
 | 
				
			||||||
 | 
					+    <content url="file://$MODULE_DIR$">
 | 
				
			||||||
 | 
					+      <excludeFolder url="file://$MODULE_DIR$/venv" />
 | 
				
			||||||
 | 
					+    </content>
 | 
				
			||||||
 | 
					+    <orderEntry type="inheritedJdk" />
 | 
				
			||||||
 | 
					     <orderEntry type="sourceFolder" forTests="false" />
 | 
				
			||||||
 | 
					   </component>
 | 
				
			||||||
 | 
					   <component name="TestRunnerService">
 | 
				
			||||||
 | 
					Index: .idea/misc.xml
 | 
				
			||||||
 | 
					IDEA additional info:
 | 
				
			||||||
 | 
					Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
 | 
				
			||||||
 | 
					<+><?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectRootManager\" version=\"2\" project-jdk-name=\"Python 3.7 (pyuserconfig)\" project-jdk-type=\"Python SDK\" />\n</project>
 | 
				
			||||||
 | 
					Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
 | 
				
			||||||
 | 
					<+>UTF-8
 | 
				
			||||||
 | 
					===================================================================
 | 
				
			||||||
 | 
					diff --git a/.idea/misc.xml b/.idea/misc.xml
 | 
				
			||||||
 | 
					--- a/.idea/misc.xml	(revision cba08629cbfd9427213cb8e1719d2ce1e601bdfc)
 | 
				
			||||||
 | 
					+++ b/.idea/misc.xml	(date 1711709021140)
 | 
				
			||||||
 | 
					@@ -1,4 +1,4 @@
 | 
				
			||||||
 | 
					 <?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="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (pyuserconfig)" project-jdk-type="Python SDK" />
 | 
				
			||||||
 | 
					 </project>
 | 
				
			||||||
 | 
					\ No newline at end of file
 | 
				
			||||||
							
								
								
									
										4
									
								
								.idea/shelf/Uncommitted_changes_before_Checkout_at_29_03_2024_21_55__Changes_.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.idea/shelf/Uncommitted_changes_before_Checkout_at_29_03_2024_21_55__Changes_.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					<changelist name="Uncommitted_changes_before_Checkout_at_29_03_2024_21_55_[Changes]" date="1711745731399" recycled="true" deleted="true">
 | 
				
			||||||
 | 
					  <option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Uncommitted_changes_before_Checkout_at_29_03_2024_21_55_[Changes]/shelved.patch" />
 | 
				
			||||||
 | 
					  <option name="DESCRIPTION" value="Uncommitted changes before Checkout at 29/03/2024 21:55 [Changes]" />
 | 
				
			||||||
 | 
					</changelist>
 | 
				
			||||||
@@ -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
 | 
					 | 
				
			||||||
							
								
								
									
										56
									
								
								cli/__init__.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										56
									
								
								cli/__init__.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					import os
 | 
				
			||||||
 | 
					import argparse
 | 
				
			||||||
 | 
					from userconfig.cfgfile import Conf
 | 
				
			||||||
 | 
					from userconfig.tools import Debug
 | 
				
			||||||
 | 
					from userconfig.checks import classes_for_host
 | 
				
			||||||
 | 
					from userconfig import Userconfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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()
 | 
				
			||||||
 | 
					    debug = Debug()
 | 
				
			||||||
 | 
					    debug.set_verbose(cmdline.verbose)
 | 
				
			||||||
 | 
					    cfg = Conf(filename=cmdline.file, debug=debug)
 | 
				
			||||||
 | 
					    uc = Userconfig(cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cfg.debug.stdout(f"Verbose level is {cfg.debug.get_verbose()}", 1)
 | 
				
			||||||
 | 
					    cfg.debug.stdout("================ main ===============", 1)
 | 
				
			||||||
 | 
					    temp_classes = ""
 | 
				
			||||||
 | 
					    for h in classes_for_host():
 | 
				
			||||||
 | 
					        temp_classes = temp_classes + str(h) + ","
 | 
				
			||||||
 | 
					    cfg.debug.stdout("+++ Current host is in classes %s" % temp_classes, 1)
 | 
				
			||||||
 | 
					    configdir = cfg.get("configdir")
 | 
				
			||||||
 | 
					    for d in os.listdir(configdir):
 | 
				
			||||||
 | 
					        name = configdir+"/"+d
 | 
				
			||||||
 | 
					        cfg.debug.stdout("+++ Working in %s" % name, 1)
 | 
				
			||||||
 | 
					        if not os.path.isdir(name):
 | 
				
			||||||
 | 
					            cfg.debug.stdout("--- %s is not a directory, skipping." % name, 3)
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        elif d.startswith(".svn") or d.startswith(".git"):
 | 
				
			||||||
 | 
					            cfg.debug.stdout("--- %s is .svn or .git, skipping." % name, 3)
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        elif os.path.isfile(name+"/.ignore"):
 | 
				
			||||||
 | 
					            cfg.debug.stdout("--- %s contains file .ignore, skipping." % name, 3)
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            cfg.debug.stdout("+++ Processing files in %s" % name, 2)
 | 
				
			||||||
 | 
					            (destfiles, dirConfig) = uc.workdir(name)
 | 
				
			||||||
 | 
					            if isinstance(destfiles, dict):
 | 
				
			||||||
 | 
					                if len(destfiles.keys()) > 0:
 | 
				
			||||||
 | 
					                    cfg.debug.stdout("+++ Building %d files: %s" % (len(destfiles.keys()), destfiles.keys()), 3)
 | 
				
			||||||
 | 
					                    uc.process_all_files(destfiles, dirConfig)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                cfg.debug.stdout("--- No files found for %s, skipping." % name, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										19
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					[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" ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[tool.setuptools.data-files]
 | 
				
			||||||
 | 
					"etc" = [ "userconfig2.conf" ]
 | 
				
			||||||
							
								
								
									
										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()
 | 
				
			||||||
 | 
					 | 
				
			||||||
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'])]
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
@@ -1,6 +0,0 @@
 | 
				
			|||||||
[Main]
 | 
					 | 
				
			||||||
configdir = $HOME/.userconfig
 | 
					 | 
				
			||||||
configfile = userconfig.cfg
 | 
					 | 
				
			||||||
debug = 0
 | 
					 | 
				
			||||||
stamp = %userconfig_generated 1.0%
 | 
					 | 
				
			||||||
stampreplace = $userconfig_stamp$
 | 
					 | 
				
			||||||
							
								
								
									
										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()
 | 
					 | 
				
			||||||
							
								
								
									
										175
									
								
								userconfig/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								userconfig/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,175 @@
 | 
				
			|||||||
 | 
					from userconfig.tools import get_config
 | 
				
			||||||
 | 
					import subprocess
 | 
				
			||||||
 | 
					from userconfig.checks import classes_for_host
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					from userconfig.tools import diff, user_config_generated, backup_file, copy_file
 | 
				
			||||||
 | 
					import time
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import tempfile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Userconfig:
 | 
				
			||||||
 | 
					    _cfg = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, cfg):
 | 
				
			||||||
 | 
					        self._cfg = cfg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def build_file(self, 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 = []
 | 
				
			||||||
 | 
					        self._cfg.debug.stdout("   ================ build_file ===============", 1)
 | 
				
			||||||
 | 
					        if commentstring != "":
 | 
				
			||||||
 | 
					            self._cfg.debug.stdout("   +++ commentstring found, adding header.", 3)
 | 
				
			||||||
 | 
					            content.append(commentstring + " " + self._cfg.get("stamp") + " " + time.strftime("%+") + "\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for f in classfiles:
 | 
				
			||||||
 | 
					            self._cfg.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(self._cfg.get("stampreplace")), filecontent):
 | 
				
			||||||
 | 
					                    self._cfg.debug.stdout("   +++ commentstring empty, replacing stamp in file", 3)
 | 
				
			||||||
 | 
					                    filecontent = re.sub(re.escape(self._cfg.get("stampreplace")), self._cfg.get("stamp"),
 | 
				
			||||||
 | 
					                                         filecontent)
 | 
				
			||||||
 | 
					            content.append(filecontent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        (tempfd, tempfilename) = tempfile.mkstemp(prefix=os.path.basename(destfile), dir="/tmp")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            fp = os.fdopen(tempfd, "w")
 | 
				
			||||||
 | 
					        except Exception as e:
 | 
				
			||||||
 | 
					            self._cfg.debug.stderr(f"Cannot write to temporary file {tempfilename}: {e}")
 | 
				
			||||||
 | 
					            os.remove(tempfilename)
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					        self._cfg.debug.stdout("   +++ Writing merged files into tempfile %s." % tempfilename, 3)
 | 
				
			||||||
 | 
					        for block in content:
 | 
				
			||||||
 | 
					            fp.write(block)
 | 
				
			||||||
 | 
					            fp.write("\n")
 | 
				
			||||||
 | 
					        fp.close()
 | 
				
			||||||
 | 
					        self._cfg.debug.stdout("   ================ build_file ===============", 1)
 | 
				
			||||||
 | 
					        return tempfilename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_all_files(self, destfiles, dir_config):
 | 
				
			||||||
 | 
					        """processes all files in destfiles, generate files from classes, compare and copy if necessary"""
 | 
				
			||||||
 | 
					        self._cfg.debug.stdout("   ================ process_all_files ===============", 1)
 | 
				
			||||||
 | 
					        for df in destfiles.keys():
 | 
				
			||||||
 | 
					            self._cfg.debug.stdout("   ??? Processing source files for %s." % df, 2)
 | 
				
			||||||
 | 
					            if not os.path.exists(os.path.dirname(df)):
 | 
				
			||||||
 | 
					                self._cfg.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)):
 | 
				
			||||||
 | 
					                self._cfg.debug.stdout(f"   --- Destination directory {os.path.dirname(df)} does not exist, skipping.",
 | 
				
			||||||
 | 
					                                       1)
 | 
				
			||||||
 | 
					                return False
 | 
				
			||||||
 | 
					            # assemble file to tmp
 | 
				
			||||||
 | 
					            commentstring = ""
 | 
				
			||||||
 | 
					            if dir_config.check(section="Main", option="commentstring"):
 | 
				
			||||||
 | 
					                commentstring = dir_config.get(section="Main", option="commentstring")
 | 
				
			||||||
 | 
					                self._cfg.debug.stdout("   +++ Found commentstring %s in %s" % (commentstring, df), 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            tempfilename = self.build_file(destfiles[df], df, commentstring)
 | 
				
			||||||
 | 
					            if not tempfilename:
 | 
				
			||||||
 | 
					                self._cfg.debug.stdout("   --- Error while creating temp file for %s, skipping." % df, 1)
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            self._cfg.debug.stdout("   +++ Merged files %s for %s into %s" % (str(destfiles[df]), df, tempfilename), 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # diff assembled file and config file
 | 
				
			||||||
 | 
					            if diff(df, tempfilename, commentstring, self._cfg):
 | 
				
			||||||
 | 
					                self._cfg.debug.stdout("File %s has changed" % df, 0)
 | 
				
			||||||
 | 
					                if not user_config_generated(df, self._cfg):
 | 
				
			||||||
 | 
					                    self._cfg.debug.stdout("   +++ %s not generated by userconfig, backing up." % df, 2)
 | 
				
			||||||
 | 
					                    # file not generated from userconfig -> back up
 | 
				
			||||||
 | 
					                    backup_file(df, self._cfg)
 | 
				
			||||||
 | 
					                # copy tmp file to real location
 | 
				
			||||||
 | 
					                self._cfg.debug.stdout("Copy %s to %s." % (tempfilename, df), 0)
 | 
				
			||||||
 | 
					                copy_file(tempfilename, df, self._cfg)
 | 
				
			||||||
 | 
					            # remove tmp
 | 
				
			||||||
 | 
					            self._cfg.debug.stdout("   +++ Removing temporary file %s." % tempfilename, 2)
 | 
				
			||||||
 | 
					            os.remove(tempfilename)
 | 
				
			||||||
 | 
					        self._cfg.debug.stdout("   ================ process_all_files ===============", 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def workconf(self, directory, depth=2):
 | 
				
			||||||
 | 
					        """walks through directory, collecting all filenames, returns list of all filenames"""
 | 
				
			||||||
 | 
					        dirs = os.listdir(directory)
 | 
				
			||||||
 | 
					        ret = []
 | 
				
			||||||
 | 
					        self._cfg.debug.stdout("   ================ workconf ===============", 1)
 | 
				
			||||||
 | 
					        self._cfg.debug.stdout("   Finding files in directory %s." % directory, 4)
 | 
				
			||||||
 | 
					        for d in dirs:
 | 
				
			||||||
 | 
					            name = directory + "/" + d
 | 
				
			||||||
 | 
					            if os.path.isdir(name):
 | 
				
			||||||
 | 
					                self.workconf(name, depth + 1)
 | 
				
			||||||
 | 
					            if name.endswith(".swp"):
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            if d == ".svn":
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            ret.append(name)
 | 
				
			||||||
 | 
					            self._cfg.debug.stdout("   +++ Found file %s in directory %s" % (name, directory), 4)
 | 
				
			||||||
 | 
					        self._cfg.debug.stdout("   ================ workconf ===============", 1)
 | 
				
			||||||
 | 
					        return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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 + "/" + self._cfg.get("configfile"), self._cfg)
 | 
				
			||||||
 | 
					        if not dir_config:
 | 
				
			||||||
 | 
					            self._cfg.debug.stdout(f'   --- Cannot read config file {self._cfg.get("configfile")} in {directory}, '
 | 
				
			||||||
 | 
					                                   f'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 = {}
 | 
				
			||||||
 | 
					        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):
 | 
				
			||||||
 | 
					            # build classes directory
 | 
				
			||||||
 | 
					            if h[0] != "":
 | 
				
			||||||
 | 
					                classdir = directory+"/"+h[0]+"_"+h[1]
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                classdir = directory+"/"+h[1]
 | 
				
			||||||
 | 
					            self._cfg.debug.stdout("   ??? Looking for directory %s." % classdir, 4)
 | 
				
			||||||
 | 
					            # if class directory exists
 | 
				
			||||||
 | 
					            if os.path.isdir(classdir):
 | 
				
			||||||
 | 
					                self._cfg.debug.stdout("   +++ Found directory %s, getting files." % classdir, 4)
 | 
				
			||||||
 | 
					                # get list of files within this class directory
 | 
				
			||||||
 | 
					                tempfiles = self.workconf(classdir)
 | 
				
			||||||
 | 
					                self._cfg.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 destname not in destfiles:
 | 
				
			||||||
 | 
					                        destfiles[destname] = []
 | 
				
			||||||
 | 
					                    destfiles[destname].append(f)  # append each file to dict
 | 
				
			||||||
 | 
					                    self._cfg.debug.stdout(f"   +++ Added file to {destname}, now {len(destfiles[destname])} files: "
 | 
				
			||||||
 | 
					                                           f"{destfiles[destname]}", 4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._cfg.debug.stdout("   === workdir: %s, Files: %s" % (directory, str(destfiles)), 3)
 | 
				
			||||||
 | 
					        self._cfg.debug.stdout("   ================ workdir ===============", 1)
 | 
				
			||||||
 | 
					        return destfiles, dir_config
 | 
				
			||||||
							
								
								
									
										62
									
								
								userconfig/cfgfile.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								userconfig/cfgfile.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					import configparser
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Conf(object):
 | 
				
			||||||
 | 
					    _confobj = configparser.ConfigParser(os.environ)
 | 
				
			||||||
 | 
					    _cfgfiles = []
 | 
				
			||||||
 | 
					    debug = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, filename=None, debug=None, force_filename=False):
 | 
				
			||||||
 | 
					        if debug:
 | 
				
			||||||
 | 
					            self.set_debug(debug)
 | 
				
			||||||
 | 
					        filenames = []
 | 
				
			||||||
 | 
					        if filename:
 | 
				
			||||||
 | 
					            filenames.append(filename)
 | 
				
			||||||
 | 
					        if not force_filename:
 | 
				
			||||||
 | 
					            if os.path.isfile(f'{os.environ.get("HOME")}/etc/userconfig2.conf'):
 | 
				
			||||||
 | 
					                filenames.append(f'{os.environ.get("HOME")}/etc/userconfig2.conf')
 | 
				
			||||||
 | 
					            if os.path.isfile(f'{sys.prefix}/etc/userconfig2.conf'):
 | 
				
			||||||
 | 
					                filenames.append(f'{sys.prefix}/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,49 @@
 | 
				
			|||||||
#!/usr/bin/env python3
 | 
					 | 
				
			||||||
# encoding: utf-8
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
Tools.py
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Created by Marcus Stoegbauer on 2013-01-12.
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import Userconfig.cfgfile as cfgfile
 | 
					from userconfig.cfgfile import Conf
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
import time
 | 
					import time
 | 
				
			||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Debug(object):
 | 
					class Debug:
 | 
				
			||||||
    verbose = 0
 | 
					    _verbose = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, verbose=0):
 | 
					    def __init__(self, verbose=0):
 | 
				
			||||||
        self.setverbose(verbose)
 | 
					        self.set_verbose(verbose)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setverbose(self, verbose):
 | 
					    def set_verbose(self, verbose):
 | 
				
			||||||
        """docstring for setverbose"""
 | 
					        self._verbose = verbose
 | 
				
			||||||
        self.verbose = verbose
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def addverbose(self):
 | 
					    def add_verbose(self):
 | 
				
			||||||
        """docstring for setverbose"""
 | 
					        self._verbose += 1
 | 
				
			||||||
        self.verbose += 1
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def debug(self, out, level=0):
 | 
					    def get_verbose(self):
 | 
				
			||||||
        """docstring for debug"""
 | 
					        return self._verbose
 | 
				
			||||||
        if self.verbose >= level:
 | 
					
 | 
				
			||||||
 | 
					    def stdout(self, out, level=0):
 | 
				
			||||||
 | 
					        if self._verbose >= level:
 | 
				
			||||||
            print(out)
 | 
					            print(out)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def stderr(self, out, level=0):
 | 
				
			||||||
def error(out):
 | 
					        if self._verbose >= level:
 | 
				
			||||||
    """Print error on stderr"""
 | 
					 | 
				
			||||||
            print(str(out)+"\n", file=sys.stderr)
 | 
					            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"""
 | 
					    """reads filename as config, checks for DEST parameter and returns cfgfile object"""
 | 
				
			||||||
    ret = None
 | 
					 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        ret = cfgfile.Conf(filename)
 | 
					        ret = Conf(filename)
 | 
				
			||||||
    except:
 | 
					    except ValueError:
 | 
				
			||||||
        error("Error reading config file %s" % filename)
 | 
					        cfg.debug.stderr("Error reading config file %s" % filename)
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					 | 
				
			||||||
    # check for DEST parameter
 | 
					    # check for DEST parameter
 | 
				
			||||||
    if not ret.check("Main", "dest"):
 | 
					    if not ret.check(section="Main", option="dest"):
 | 
				
			||||||
        error("No DEST in config file %s" % filename)
 | 
					        cfg.debug.stderr("No dest in config file %s" % filename)
 | 
				
			||||||
        return False
 | 
					        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 /
 | 
					    # make sure DEST ends with /
 | 
				
			||||||
    if not ret.get("Main", "dest").endswith("/"):
 | 
					    if not ret.get(section="Main", option="dest").endswith("/"):
 | 
				
			||||||
        ret.set("Main", "dest", ret.get("Main", "dest")+"/")
 | 
					        ret.set(section="Main", option="dest", value=ret.get(section="Main", option="dest")+"/")
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ret
 | 
					    return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -70,21 +52,22 @@ def read_skip_comment(fp, commentstring):
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
    for line in fp:
 | 
					    for line in fp:
 | 
				
			||||||
        line = line[:-1]
 | 
					        line = line[:-1]
 | 
				
			||||||
        if (commentstring != "" and not re.match("^"+re.escape(commentstring), line)) and line !="" and not re.match("^\s+$", line):
 | 
					        if ((commentstring != "" and not re.match("^"+re.escape(commentstring), line)) and line != "" and
 | 
				
			||||||
 | 
					                not re.match(r"^\s+$", line)):
 | 
				
			||||||
            yield line
 | 
					            yield line
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def diff(destfile, tempfile, commentstring, debug):
 | 
					def diff(destfile, tempfile, commentstring, cfg):
 | 
				
			||||||
    """diff destfile and tempfile, returns True if files differ, False if they are the same"""
 | 
					    """diff destfile and tempfile, returns True if files differ, False if they are the same"""
 | 
				
			||||||
    debug.debug("Diffing %s and %s" % (destfile, tempfile), 3)
 | 
					    cfg.debug.stdout("Diffing %s and %s, comment: %s" % (destfile, tempfile, commentstring), 3)
 | 
				
			||||||
    if not os.path.isfile(destfile):
 | 
					    if not os.path.isfile(destfile):
 | 
				
			||||||
        debug.debug("Destfile %s does not exist, returning True." % destfile, 3)
 | 
					        cfg.debug.stdout("Destfile %s does not exist, returning True." % destfile, 3)
 | 
				
			||||||
        # destfile does not exist -> copy tempfile over
 | 
					        # destfile does not exist -> copy tempfile over
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
    # if not destfile
 | 
					    # if not destfile
 | 
				
			||||||
    if not os.path.isfile(tempfile):
 | 
					    if not os.path.isfile(tempfile):
 | 
				
			||||||
        # tempfile does not exist, this should never happen
 | 
					        # tempfile does not exist, this should never happen
 | 
				
			||||||
        error("Temporary file %s does not exist, this should not happen." % tempfile)
 | 
					        cfg.debug.stderr("Temporary file %s does not exist, this should not happen." % tempfile)
 | 
				
			||||||
        sys.exit(1)
 | 
					        sys.exit(1)
 | 
				
			||||||
    # if not tempfile
 | 
					    # if not tempfile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -95,13 +78,13 @@ def diff(destfile, tempfile, commentstring, debug):
 | 
				
			|||||||
        if line1 != line2:
 | 
					        if line1 != line2:
 | 
				
			||||||
            fp1.close()
 | 
					            fp1.close()
 | 
				
			||||||
            fp2.close()
 | 
					            fp2.close()
 | 
				
			||||||
            debug.debug("%s differs, return true" % destfile, 3)
 | 
					            cfg.debug.stdout("%s differs, return true" % destfile, 3)
 | 
				
			||||||
            return True
 | 
					            return True
 | 
				
			||||||
        # if differ
 | 
					        # if differ
 | 
				
			||||||
    # for line
 | 
					    # for line
 | 
				
			||||||
    fp1.close()
 | 
					    fp1.close()
 | 
				
			||||||
    fp2.close()
 | 
					    fp2.close()
 | 
				
			||||||
    debug.debug("%s is the same, return false" % destfile, 3)
 | 
					    cfg.debug.stdout("%s is the same, return false" % destfile, 3)
 | 
				
			||||||
    return False
 | 
					    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -112,47 +95,47 @@ def user_config_generated(filename, cfg):
 | 
				
			|||||||
        # filename does not exist, so it was not generated by userconfig
 | 
					        # filename does not exist, so it was not generated by userconfig
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not cfg.check("Main","stamp"):
 | 
					    if not cfg.check("stamp"):
 | 
				
			||||||
        # no STAMP in userconfig.cfg, so no way to check if file was generated by userconfig
 | 
					        # no STAMP in userconfig.cfg, so no way to check if file was generated by userconfig
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fp = open(filename, "r")
 | 
					    fp = open(filename, "r")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for line in fp:
 | 
					    for line in fp:
 | 
				
			||||||
        if re.search(re.escape(cfg.get("Main","stamp")), line):
 | 
					        if re.search(re.escape(cfg.get("stamp")), line):
 | 
				
			||||||
            return True
 | 
					            return True
 | 
				
			||||||
    return False
 | 
					    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def backup_file(filename, debug):
 | 
					def backup_file(filename, cfg):
 | 
				
			||||||
    """make backup of filename, returns True if backup is successful, False else"""
 | 
					    """make backup of filename, returns True if backup is successful, False else"""
 | 
				
			||||||
    if os.path.isfile(filename):
 | 
					    if os.path.isfile(filename):
 | 
				
			||||||
        debug.debug("%s exists, finding backup name." % filename, 3)
 | 
					        cfg.debug.stdout("%s exists, finding backup name." % filename, 3)
 | 
				
			||||||
        backupname = filename+".userconfig."+time.strftime("%F")
 | 
					        backupname = filename+".userconfig."+time.strftime("%F")
 | 
				
			||||||
        testbackupname = backupname
 | 
					        testbackupname = backupname
 | 
				
			||||||
        counter = 0
 | 
					        counter = 0
 | 
				
			||||||
        while os.path.isfile(testbackupname):
 | 
					        while os.path.isfile(testbackupname):
 | 
				
			||||||
            counter += 1
 | 
					            counter += 1
 | 
				
			||||||
            testbackupname = backupname+"."+str(counter)
 | 
					            testbackupname = backupname+"."+str(counter)
 | 
				
			||||||
        debug.debug("Renaming %s to %s" % (filename, testbackupname), 1)
 | 
					        cfg.debug.stdout("Renaming %s to %s" % (filename, testbackupname), 1)
 | 
				
			||||||
        os.rename(filename, testbackupname)
 | 
					        os.rename(filename, testbackupname)
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        debug.debug("%s does not exist, do not need backup." % filename, 3)
 | 
					        cfg.debug.stdout("%s does not exist, do not need backup." % filename, 3)
 | 
				
			||||||
    return False
 | 
					    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def copy_file(sourcefile, destfile, debug):
 | 
					def copy_file(sourcefile, destfile, cfg):
 | 
				
			||||||
    """copy sourcefile to destfile, returns True if successful, False else"""
 | 
					    """copy sourcefile to destfile, returns True if successful, False else"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if os.path.isfile(sourcefile):
 | 
					    if os.path.isfile(sourcefile):
 | 
				
			||||||
        # sourcefile exists
 | 
					        # sourcefile exists
 | 
				
			||||||
        debug.debug("Source file %s exists, proceeding with copy." % sourcefile, 3)
 | 
					        cfg.debug.stdout("Source file %s exists, proceeding with copy." % sourcefile, 3)
 | 
				
			||||||
        if not os.path.isfile(destfile) or os.access(destfile, os.W_OK):
 | 
					        if not os.path.isfile(destfile) or os.access(destfile, os.W_OK):
 | 
				
			||||||
            debug.debug("Copying %s to %s" % (sourcefile, destfile), 1)
 | 
					            cfg.debug.stdout("Copying %s to %s" % (sourcefile, destfile), 1)
 | 
				
			||||||
            shutil.copy(sourcefile, destfile)
 | 
					            shutil.copy(sourcefile, destfile)
 | 
				
			||||||
            return True
 | 
					            return True
 | 
				
			||||||
            # destfile is writable
 | 
					            # destfile is writable
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            debug.debug("Destination file %s does not exist or is not writable." % destfile, 3)
 | 
					            cfg.debug.stdout("Destination file %s does not exist or is not writable." % destfile, 3)
 | 
				
			||||||
    return False
 | 
					    return False
 | 
				
			||||||
							
								
								
									
										6
									
								
								userconfig2.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								userconfig2.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					[userconfig]
 | 
				
			||||||
 | 
					configdir = %(HOME)s/.userconfig
 | 
				
			||||||
 | 
					configfile = userconfig2.cfg
 | 
				
			||||||
 | 
					debug = 0
 | 
				
			||||||
 | 
					stamp = %%userconfig_generated 1.0%%
 | 
				
			||||||
 | 
					stampreplace = $userconfig_stamp$
 | 
				
			||||||
		Reference in New Issue
	
	Block a user