UBUNTU: [Packaging] annotations: various code cleanups

kconfig: Fix pylint violations

Fix the following:
R0205: Class 'Config' inherits from object, can be safely removed from bases in python3 (useless-object-inheritance)
E1101: Instance of 'Config' has no '_parse' member (no-member)
W0613: Unused argument 'arch' (unused-argument)
W0613: Unused argument 'flavour' (unused-argument)
W1514: Using open without explicitly specifying an encoding (unspecified-encoding)
R0201: Method could be a function (no-self-use)
E1101: Instance of 'Config' has no 'config' member (no-member)
W0707: Consider explicitly re-raising using the 'from' keyword (raise-missing-from)
W0105: String statement has no effect (pointless-string-statement)
W0123: Use of eval (eval-used)
W0102: Dangerous default value [] as argument (dangerous-default-value)
R1723: Unnecessary "elif" after "break" (no-else-break)
R1705: Unnecessary "elif" after "return" (no-else-return)
R1704: Redefining argument with the local name 'arch' (redefined-argument-from-local)

Signed-off-by: Juerg Haefliger <juergh@proton.me>
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
This commit is contained in:
Andrea Righi
2023-02-13 08:33:41 +01:00
committed by Paolo Pisati
parent 17aa0ecba6
commit 7ecfc3dd9d
2 changed files with 68 additions and 37 deletions
+25 -7
View File
@@ -8,9 +8,10 @@ sys.dont_write_bytecode = True
import os
import argparse
import json
from kconfig.annotations import Annotation, KConfig
from signal import signal, SIGPIPE, SIG_DFL
from kconfig.annotations import Annotation, KConfig
VERSION = '0.1'
SKIP_CONFIGS = (
@@ -28,6 +29,7 @@ SKIP_CONFIGS = (
'CONFIG_BINDGEN_VERSION_TEXT',
)
def make_parser():
parser = argparse.ArgumentParser(
description='Manage Ubuntu kernel .config and annotations',
@@ -68,18 +70,22 @@ def make_parser():
help='Validate kernel .config with annotations')
return parser
_ARGPARSER = make_parser()
def arg_fail(message):
print(message)
_ARGPARSER.print_usage()
exit(1)
sys.exit(1)
def print_result(config, res):
if res is not None and config not in res:
res = {config or '*': res}
print(json.dumps(res, indent=4))
def do_query(args):
if args.arch is None and args.flavour is not None:
arg_fail('error: --flavour requires --arch')
@@ -87,19 +93,23 @@ def do_query(args):
res = a.search_config(config=args.config, arch=args.arch, flavour=args.flavour)
print_result(args.config, res)
def do_autocomplete(args):
a = Annotation(args.file)
res = (c.removeprefix('CONFIG_') for c in a.search_config())
print('complete -W "{}" annotations'.format(' '.join(res)))
res_str = ' '.join(res)
print(f'complete -W "{res_str}" annotations')
def do_source(args):
if args.config is None:
arg_fail('error: --source requires --config')
if not os.path.exists('tags'):
print('tags not found in the current directory, try: `make tags`')
exit(1)
sys.exit(1)
os.system(f'vim -t {args.config}')
def do_note(args):
if args.config is None:
arg_fail('error: --note requires --config')
@@ -116,6 +126,7 @@ def do_note(args):
res = a.search_config(config=args.config)
print_result(args.config, res)
def do_write(args):
if args.config is None:
arg_fail('error: --write requires --config')
@@ -135,6 +146,7 @@ def do_write(args):
res = a.search_config(config=args.config)
print_result(args.config, res)
def do_export(args):
if args.arch is None:
arg_fail('error: --export requires --arch')
@@ -143,6 +155,7 @@ def do_export(args):
if conf:
print(a.to_config(conf))
def do_import(args):
if args.arch is None:
arg_fail('error: --arch is required with --import')
@@ -159,6 +172,7 @@ def do_import(args):
# Save back to annotations
a.save(args.file)
def do_update(args):
if args.arch is None:
arg_fail('error: --arch is required with --update')
@@ -174,6 +188,7 @@ def do_update(args):
# Save back to annotations
a.save(args.file)
def do_check(args):
# Determine arch and flavour
if args.arch is None:
@@ -208,7 +223,8 @@ def do_check(args):
total += 1
print(f"check-config: {good}/{total} checks passed -- exit {ret}")
exit(ret)
sys.exit(ret)
def autodetect_annotations(args):
if args.file:
@@ -216,11 +232,12 @@ def autodetect_annotations(args):
# If --file/-f isn't specified try to automatically determine the right
# location of the annotations file looking at debian/debian.env.
try:
with open('debian/debian.env', 'rt') as fd:
with open('debian/debian.env', 'rt', encoding='utf-8') as fd:
args.file = fd.read().rstrip().split('=')[1] + '/config/annotations'
except Exception:
except (FileNotFoundError, IndexError):
arg_fail('error: could not determine DEBDIR, try using: --file/-f')
def main():
# Prevent broken pipe errors when showing output in pipe to other tools
# (less for example)
@@ -252,5 +269,6 @@ def main():
else:
do_query(args)
if __name__ == '__main__':
main()
+43 -30
View File
@@ -7,20 +7,26 @@ import json
import re
import shutil
import tempfile
from abc import abstractmethod
from ast import literal_eval
from os.path import dirname, abspath
class Config(object):
def __init__(self, fname: str, arch: str = None, flavour: str = None):
class Config():
def __init__(self, fname):
"""
Basic configuration file object
"""
self.fname = fname
self.config = {}
raw_data = self._load(fname)
self._parse(raw_data)
def _load(self, fname: str) -> str:
with open(fname, 'rt') as fd:
@staticmethod
def _load(fname: str) -> str:
with open(fname, 'rt', encoding='utf-8') as fd:
data = fd.read()
return data.rstrip()
@@ -28,12 +34,17 @@ class Config(object):
""" Return a JSON representation of the config """
return json.dumps(self.config, indent=4)
@abstractmethod
def _parse(self, data: str):
pass
class KConfig(Config):
"""
Parse a .config file, individual config options can be accessed via
.config[<CONFIG_OPTION>]
"""
def _parse(self, data: str) -> dict:
def _parse(self, data: str):
self.config = {}
for line in data.splitlines():
m = re.match(r'^# (CONFIG_.*) is not set$', line)
@@ -45,6 +56,7 @@ class KConfig(Config):
self.config[m.group(1)] = literal_eval("'" + m.group(2) + "'")
continue
class Annotation(Config):
"""
Parse body of annotations file
@@ -104,17 +116,17 @@ class Annotation(Config):
raise Exception('syntax error')
self.config[conf] = entry
except Exception as e:
raise Exception(str(e) + f', line = {line}')
raise Exception(str(e) + f', line = {line}') from e
continue
# Invalid line
raise Exception(f'invalid line: {line}')
"""
Parse main annotations file, individual config options can be accessed via
self.config[<CONFIG_OPTION>]
"""
def _parse(self, data: str) -> dict:
def _parse(self, data: str):
"""
Parse main annotations file, individual config options can be accessed
via self.config[<CONFIG_OPTION>]
"""
self.config = {}
self.arch = []
self.flavour = []
@@ -135,7 +147,7 @@ class Annotation(Config):
self.flavour = list(m.group(1).split(' '))
m = re.match(r'^# FLAVOUR_DEP: (.*)', line)
if m:
self.flavour_dep = eval(m.group(1))
self.flavour_dep = literal_eval(m.group(1))
self.header += line + "\n"
else:
break
@@ -180,12 +192,12 @@ class Annotation(Config):
flavour = arch
self.config[config]['policy'][flavour] = value
else:
for arch in self.arch:
self.config[config]['policy'][arch] = value
for a in self.arch:
self.config[config]['policy'][a] = value
if note is not None:
self.config[config]['note'] = "'" + note.replace("'", '') + "'"
def update(self, c: KConfig, arch: str, flavour: str = None, configs: list = []):
def update(self, c: KConfig, arch: str, flavour: str = None, configs: list = None):
""" Merge configs from a Kconfig object into Annotation object """
# Determine if we need to import all configs or a single config
@@ -257,7 +269,7 @@ class Annotation(Config):
for flavour in arch_flavours:
if flavour not in self.config[conf]['policy']:
break
elif value is None:
if value is None:
value = self.config[conf]['policy'][flavour]
elif value != self.config[conf]['policy'][flavour]:
break
@@ -279,7 +291,8 @@ class Annotation(Config):
if not self.config[conf]['policy']:
del self.config[conf]
def _sorted(self, config):
@staticmethod
def _sorted(config):
""" Sort configs alphabetically but return configs with a note first """
w_note = []
wo_note = []
@@ -359,31 +372,31 @@ class Annotation(Config):
if config is None and arch is None:
# Get all config options for all architectures
return self.config
elif config is None and arch is not None:
if config is None and arch is not None:
# Get config options of a specific architecture
ret = {}
for c in self.config:
if 'policy' not in self.config[c]:
for c, val in self.config.items():
if 'policy' not in val:
continue
if flavour in self.config[c]['policy']:
ret[c] = self.config[c]['policy'][flavour]
elif generic != flavour and generic in self.config[c]['policy']:
ret[c] = self.config[c]['policy'][generic]
elif arch in self.config[c]['policy']:
ret[c] = self.config[c]['policy'][arch]
if flavour in val['policy']:
ret[c] = val['policy'][flavour]
elif generic != flavour and generic in val['policy']:
ret[c] = val['policy'][generic]
elif arch in val['policy']:
ret[c] = val['policy'][arch]
return ret
elif config is not None and arch is None:
if config is not None and arch is None:
# Get a specific config option for all architectures
return self.config[config] if config in self.config else None
elif config is not None and arch is not None:
if config is not None and arch is not None:
# Get a specific config option for a specific architecture
if config in self.config:
if 'policy' in self.config[config]:
if flavour in self.config[config]['policy']:
return {config: self.config[config]['policy'][flavour]}
elif generic != flavour and generic in self.config[config]['policy']:
if generic != flavour and generic in self.config[config]['policy']:
return {config: self.config[config]['policy'][generic]}
elif arch in self.config[config]['policy']:
if arch in self.config[config]['policy']:
return {config: self.config[config]['policy'][arch]}
return None