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:
committed by
Paolo Pisati
parent
17aa0ecba6
commit
7ecfc3dd9d
Vendored
+25
-7
@@ -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
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user