config file support is ready

- over.app.ConfigFile can read, create and amend config files
- fix over.cmd.format_invocation
- add join to over.text.paragraph
This commit is contained in:
Martinez 2016-05-17 20:58:53 +02:00
parent 17eda81ad2
commit 5b983a3131
6 changed files with 81 additions and 19 deletions

View file

@ -9,6 +9,7 @@ import sys
import re
import os
import shlex
import hashlib
try:
import xdg.BaseDirectory as xdg_bd
@ -112,6 +113,7 @@ class Option:
self.abbr = abbr
self.in_cfg_file = in_cfg_file
self.show_in_help = show_in_help
self.hash = hashlib.sha1(name.encode("utf-8")).hexdigest()
if is_boolean is None:
self.is_boolean = callback in (bool, callback_module.boolean, callback_module.booleans)
@ -231,6 +233,28 @@ def get_xdg_paths(appname):
# --------------------------------------------------
def serialize_callback(f):
return "%s.%s" %(f.__module__, f.__name__)
# --------------------------------------------------
def format_description(description):
colorless = text.render(description, colors=False)
lines = text.paragraph(colorless, 55, 2, join=False)
# comment them out and assemble
return "\n".join("#" + line[1:] for line in lines)
# --------------------------------------------------
def serialize_default(option):
if option.default is Option_sources.none:
return ""
else:
return cmd.format_invocation(str(x) for x in option.default)
# --------------------------------------------------
class ConfigFile:
"""
Config file object. Takes a {name: Option} dictionary and a file path, and:
@ -244,6 +268,7 @@ class ConfigFile:
self.dir = get_xdg_paths(app_name)["config"]
self.path = os.path.join(self.dir, "main.cfg")
self.print = text.Output(app_name + ".ConfigFile")
self.seen_hashes = set()
self.read_config()
self.sync_config(app_name, app_version)
@ -259,20 +284,21 @@ class ConfigFile:
for line in f:
line = line.strip()
if line and line[0] != "#": # ignore comments and empty lines
L, R = (t.strip() for t in line.split("="))
try:
option = self.options[L]
except KeyError:
raise UnknownOption(L)
if option.count > 1:
args = shlex.split(R)
if line:
if line[0] == "#":
m = re.findall("# ---- ([0-9a-f]{40}) ----", line)
if m:
self.seen_hashes.add(m[0])
else:
args = [R]
option.set_value(args, Option_sources.config_file)
L, R = (t.strip() for t in line.split("="))
try:
option = self.options[L]
except KeyError:
raise UnknownOption(L)
args = shlex.split(R)
option.set_value(args, Option_sources.config_file)
def sync_config(self, app_name, app_version):
"""
@ -292,7 +318,21 @@ class ConfigFile:
# add new or otherwise missing options
with open(self.path, "a") as f:
...
for option in self.options.values():
if option.hash not in self.seen_hashes:
self.print("adding <W>--<G>%s<.> to config file" %(option.name))
f.write(docs.config_file_item %(
option.hash,
("--{0} or --no-{0}" if (option.is_boolean and option.count == 0) else "--{0}").format(option.name),
serialize_callback(option.callback),
option.count or "no",
"" if option.count == 1 else "s",
"the last instance counts" if option.overwrite else "can be specified multiple times",
format_description(option.description),
option.name,
serialize_default(option)
))
def __repr__(self):
return "ConfigFile(%s)" %(self.path)