Refactoring & install with pyproject.toml #1

Merged
lysis merged 16 commits from toml into main 2024-03-30 10:16:16 +01:00
14 changed files with 385 additions and 474 deletions
Showing only changes of commit ef0efba96a - Show all commits

View 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
View File

@ -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.12 (userconfig)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (userconfig)" project-jdk-type="Python SDK" />
</project> </project>

View File

@ -2,7 +2,7 @@
<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" /> <orderEntry type="jdk" jdkName="Python 3.12 (userconfig)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
<component name="TestRunnerService"> <component name="TestRunnerService">

View File

View File

@ -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)

View File

@ -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
View 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
View 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" ]

View File

@ -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'])]
)

View File

@ -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
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]

View File

@ -1,67 +1,47 @@
#!/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 stdout(self, out, level=0):
"""docstring for debug""" if self._verbose >= level:
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 ret = None
try: try:
ret = cfgfile.Conf(filename) ret = Conf(filename)
except: except:
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("Main", "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("Main", "dest").endswith("/"):
ret.set("Main", "dest", ret.get("Main", "dest")+"/") ret.set("Main", "dest", ret.get("Main", "dest")+"/")
return ret return ret
@ -76,9 +56,9 @@ def read_skip_comment(fp, commentstring):
def diff(destfile, tempfile, commentstring, debug): def diff(destfile, tempfile, commentstring, debug):
"""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) debug.stdout("Diffing %s and %s" % (destfile, tempfile), 3)
if not os.path.isfile(destfile): 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 # destfile does not exist -> copy tempfile over
return True return True
# if not destfile # if not destfile
@ -95,13 +75,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) 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) debug.stdout("%s is the same, return false" % destfile, 3)
return False return False
@ -127,18 +107,18 @@ def user_config_generated(filename, cfg):
def backup_file(filename, debug): def backup_file(filename, debug):
"""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) 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) 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) debug.stdout("%s does not exist, do not need backup." % filename, 3)
return False return False
@ -147,12 +127,12 @@ def copy_file(sourcefile, destfile, debug):
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) 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) 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) debug.stdout("Destination file %s does not exist or is not writable." % destfile, 3)
return False return False