App: Use ProjectConf

Refactor App to use the new ProjectConf module for parsing make/project.conf files.

This commit

- removes the inline ad-hoc read_value() method and its nested helper functions, replacing them with ProjectConf's get_str_or_none() API.
- introduces two cached helper methods (__read_project_conf() and __get_project_conf()) to read and cache ProjectConf instances per project.
- updates get_value() to delegate to ProjectConf and moves the proj_dir lookup to only run in the version branch where it is needed.
- updates the topdir init to use __read_project_conf() with a FileNotFoundError catch for optional config files.
Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
Jan Lindemann 2026-06-09 13:17:14 +02:00
commit 9c8a09d696
Signed by: Jan Lindemann
GPG key ID: 3750640C9E25DD61

View file

@ -16,6 +16,7 @@ from typing import TYPE_CHECKING
from .lib.App import App as Base
from .lib.Distro import Distro
from .lib.log import DEBUG, ERR, log
from .lib.ProjectConf import ProjectConf
if TYPE_CHECKING:
import argparse
@ -180,6 +181,17 @@ class App(Base):
return ret
return None
@cache
def __read_project_conf(self, project_dir: str) -> ProjectConf:
return ProjectConf.read(project_dir + '/make/project.conf')
@cache
def __get_project_conf(self, project: str) -> ProjectConf:
pd = self.__proj_dir(project, False)
if pd is None:
raise Exception(f'Failed to find directory of project {project}')
return self.__read_project_conf(pd)
def __get_project_refs_cached(
self, buf, visited, spec, section, key, add_self, scope, names_only
):
@ -405,9 +417,11 @@ class App(Base):
self.___pretty_topdir = self.__format_topdir(self.___topdir, args.topdir_format)
self.__topdir_fmt = args.topdir_format
if self.___topdir is not None:
self.__top_name = self.read_value(
self.___topdir + '/make/project.conf', 'build', 'name'
)
try:
conf = self.__read_project_conf(self.__topdir)
self.__top_name = conf.get_str_or_none('build', 'name')
except FileNotFoundError:
pass
if not self.__top_name:
self.__top_name = re.sub(
'-[0-9.-]*$',
@ -529,66 +543,13 @@ class App(Base):
file.close()
return ret.rstrip()
@cache
def read_value(self, path: str, section: str, key: str) -> str | None:
def scan_section(f, key: str) -> str | None:
if key is None:
ret = ''
for line in f:
if len(line) and line[0] == '[':
break
ret += line
return ret if len(ret) else None
lines: list[str] = []
cont_line = ''
for line in f:
if len(line) and line[0] == '[':
break
cont_line += line.rstrip()
if len(cont_line) and cont_line[-1] == '\\':
cont_line = cont_line[0:-1]
continue
lines.append(cont_line)
cont_line = ''
rx = re.compile(r'^\s*' + key + r'\s*=\s*(.*)\s*$')
for line in lines:
# log(DEBUG, ' looking for "%s" in line="%s"' % (key, line))
m = re.search(rx, line)
if m is not None:
return m.group(1)
return None
def scan_section_debug(f, key: str) -> str | None:
ret = scan_section(f, key)
# log(DEBUG, ' returning', rr)
return ret
try:
# log(DEBUG, 'looking for {}::[{}].{}'.format(path, section, key))
# TODO: Parse
with open(path, 'r') as f:
if not len(section):
return scan_section(f, key)
pat = '[' + section + ']'
for line in f:
if line.rstrip() == pat:
return scan_section(f, key)
return None
except Exception:
log(DEBUG, f'Not found: {path}')
# TODO: handle this special case cleaner somewhere up the stack
if section == 'build' and key == 'libname':
return 'none'
return None
@cache
def get_value(self, project: str, section: str, key: str) -> str | None:
ret: str | None
proj_dir = self.__proj_dir(project, pretty = False)
if proj_dir is None:
raise Exception(f"Can't get project directory for {project}")
if section == 'version':
proj_dir = self.__proj_dir(project, pretty = False)
if proj_dir is None:
raise Exception(f"Can't get project directory for {project}")
proj_version_dirs = [proj_dir]
if proj_dir != self.___topdir:
proj_version_dirs.append('/usr/share/doc/packages/' + project)
@ -603,8 +564,7 @@ class App(Base):
log(DEBUG, f'Ignoring unreadable file "{version_path}"')
continue
raise Exception(f'No version file found for project "{project}"')
path = proj_dir + '/make/project.conf'
ret = self.read_value(path, section, key)
ret = self.__get_project_conf(project).get_str_or_none(section, key)
log(
DEBUG,
'Lookup %s -> %s / [%s%s] -> "%s"' %