unfinished changes, needs to be continued

This commit is contained in:
2024-03-29 21:48:06 +01:00
parent cba08629cb
commit ef0efba96a
14 changed files with 385 additions and 474 deletions

67
userconfig/__init__.py Normal file
View 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
View 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
View 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]

138
userconfig/tools.py Normal file
View File

@@ -0,0 +1,138 @@
import sys
import os
from userconfig.cfgfile import Conf
import re
import time
import shutil
class Debug():
_verbose = 0
def __init__(self, verbose=0):
self.set_verbose(verbose)
def set_verbose(self, verbose):
self._verbose = verbose
def add_verbose(self):
self._verbose += 1
def stdout(self, out, level=0):
if self._verbose >= level:
print(out)
def stderr(self, out, level=0):
if self._verbose >= level:
print(str(out)+"\n", file=sys.stderr)
def get_config(filename, cfg):
"""reads filename as config, checks for DEST parameter and returns cfgfile object"""
ret = None
try:
ret = Conf(filename)
except:
cfg.debug.stderr("Error reading config file %s" % filename)
return False
# check for DEST parameter
if not ret.check("Main", "dest"):
cfg.debug.stderr("No dest in config file %s" % filename)
return False
# make sure DEST ends with /
if not ret.get("Main", "dest").endswith("/"):
ret.set("Main", "dest", ret.get("Main", "dest")+"/")
return ret
def read_skip_comment(fp, commentstring):
"""Read line from filehandle fp and skip all empty (whitespace) lines and lines starting with commentstring
"""
for line in fp:
line = line[:-1]
if (commentstring != "" and not re.match("^"+re.escape(commentstring), line)) and line !="" and not re.match("^\s+$", line):
yield line
def diff(destfile, tempfile, commentstring, debug):
"""diff destfile and tempfile, returns True if files differ, False if they are the same"""
debug.stdout("Diffing %s and %s" % (destfile, tempfile), 3)
if not os.path.isfile(destfile):
debug.stdout("Destfile %s does not exist, returning True." % destfile, 3)
# destfile does not exist -> copy tempfile over
return True
# if not destfile
if not os.path.isfile(tempfile):
# tempfile does not exist, this should never happen
error("Temporary file %s does not exist, this should not happen." % tempfile)
sys.exit(1)
# if not tempfile
fp1 = open(tempfile)
fp2 = open(destfile)
for line1, line2 in zip(read_skip_comment(fp1, commentstring), read_skip_comment(fp2, commentstring)):
if line1 != line2:
fp1.close()
fp2.close()
debug.stdout("%s differs, return true" % destfile, 3)
return True
# if differ
# for line
fp1.close()
fp2.close()
debug.stdout("%s is the same, return false" % destfile, 3)
return False
def user_config_generated(filename, cfg):
"""returns True if filename has been generated by userconfig, False else"""
if not os.path.isfile(filename):
# filename does not exist, so it was not generated by userconfig
return False
if not cfg.check("Main","stamp"):
# no STAMP in userconfig.cfg, so no way to check if file was generated by userconfig
return False
fp = open(filename, "r")
for line in fp:
if re.search(re.escape(cfg.get("Main","stamp")), line):
return True
return False
def backup_file(filename, debug):
"""make backup of filename, returns True if backup is successful, False else"""
if os.path.isfile(filename):
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.stdout("Renaming %s to %s" % (filename, testbackupname), 1)
os.rename(filename, testbackupname)
return True
else:
debug.stdout("%s does not exist, do not need backup." % filename, 3)
return False
def copy_file(sourcefile, destfile, debug):
"""copy sourcefile to destfile, returns True if successful, False else"""
if os.path.isfile(sourcefile):
# sourcefile exists
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.stdout("Copying %s to %s" % (sourcefile, destfile), 1)
shutil.copy(sourcefile, destfile)
return True
# destfile is writable
else:
debug.stdout("Destination file %s does not exist or is not writable." % destfile, 3)
return False