mirror of
https://git.launchpad.net/~ubuntu-release/britney/+git/britney2-ubuntu
synced 2025-05-25 17:31:29 +00:00
HintParser: Support adding new hints to the parser
This includes refining "HINTS_ALL" to cover all hints added at runtime. Currently, it is not very useful. However, a later commit will allow policies to use this feature. Signed-off-by: Niels Thykier <niels@thykier.net>
This commit is contained in:
parent
13417c18e4
commit
948d15d536
19
britney.py
19
britney.py
@ -259,9 +259,10 @@ class Britney(object):
|
|||||||
For more documentation on this script, please read the Developers Reference.
|
For more documentation on this script, please read the Developers Reference.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
HINTS_HELPERS = ("easy", "hint", "remove", "block", "block-udeb", "unblock", "unblock-udeb", "approve")
|
HINTS_HELPERS = ("easy", "hint", "remove", "block", "block-udeb", "unblock", "unblock-udeb", "approve", "remark")
|
||||||
HINTS_STANDARD = ("urgent", "age-days") + HINTS_HELPERS
|
HINTS_STANDARD = ("urgent", "age-days") + HINTS_HELPERS
|
||||||
HINTS_ALL = ("force", "force-hint", "block-all") + HINTS_STANDARD
|
# ALL = {"force", "force-hint", "block-all"} | HINTS_STANDARD | registered policy hints (not covered above)
|
||||||
|
HINTS_ALL = ('ALL')
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Class constructor
|
"""Class constructor
|
||||||
@ -272,6 +273,7 @@ class Britney(object):
|
|||||||
|
|
||||||
# parse the command line arguments
|
# parse the command line arguments
|
||||||
self.policies = []
|
self.policies = []
|
||||||
|
self._hint_parser = HintParser(self)
|
||||||
self.__parse_arguments()
|
self.__parse_arguments()
|
||||||
MigrationItem.set_architectures(self.options.architectures)
|
MigrationItem.set_architectures(self.options.architectures)
|
||||||
|
|
||||||
@ -281,7 +283,6 @@ class Britney(object):
|
|||||||
self.binaries = {}
|
self.binaries = {}
|
||||||
self.all_selected = []
|
self.all_selected = []
|
||||||
self.excuses = {}
|
self.excuses = {}
|
||||||
self._hint_parser = HintParser(self)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.read_hints(self.options.hintsdir)
|
self.read_hints(self.options.hintsdir)
|
||||||
@ -442,6 +443,7 @@ class Britney(object):
|
|||||||
# minimum days for unstable-testing transition and the list of hints
|
# minimum days for unstable-testing transition and the list of hints
|
||||||
# are handled as an ad-hoc case
|
# are handled as an ad-hoc case
|
||||||
MINDAYS = {}
|
MINDAYS = {}
|
||||||
|
|
||||||
self.HINTS = {'command-line': self.HINTS_ALL}
|
self.HINTS = {'command-line': self.HINTS_ALL}
|
||||||
with open(self.options.config, encoding='utf-8') as config:
|
with open(self.options.config, encoding='utf-8') as config:
|
||||||
for line in config:
|
for line in config:
|
||||||
@ -2790,6 +2792,8 @@ class Britney(object):
|
|||||||
# so ensure readline does not split on these characters.
|
# so ensure readline does not split on these characters.
|
||||||
readline.set_completer_delims(readline.get_completer_delims().replace('-', '').replace('/', ''))
|
readline.set_completer_delims(readline.get_completer_delims().replace('-', '').replace('/', ''))
|
||||||
|
|
||||||
|
known_hints = self._hint_parser.registered_hints
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# read the command from the command line
|
# read the command from the command line
|
||||||
try:
|
try:
|
||||||
@ -2803,11 +2807,6 @@ class Britney(object):
|
|||||||
# quit the hint tester
|
# quit the hint tester
|
||||||
if user_input and user_input[0] in ('quit', 'exit'):
|
if user_input and user_input[0] in ('quit', 'exit'):
|
||||||
break
|
break
|
||||||
elif user_input and user_input[0] in ('remove', 'approve', 'urgent', 'age-days',
|
|
||||||
'block', 'block-udeb', 'unblock', 'unblock-udeb',
|
|
||||||
'block-all', 'force'):
|
|
||||||
self._hint_parser.parse_hints('hint-tester', Britney.HINTS_ALL, '<stdin>', [' '.join(user_input)])
|
|
||||||
self.write_excuses()
|
|
||||||
# run a hint
|
# run a hint
|
||||||
elif user_input and user_input[0] in ('easy', 'hint', 'force-hint'):
|
elif user_input and user_input[0] in ('easy', 'hint', 'force-hint'):
|
||||||
try:
|
try:
|
||||||
@ -2816,6 +2815,10 @@ class Britney(object):
|
|||||||
self.printuninstchange()
|
self.printuninstchange()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
continue
|
continue
|
||||||
|
elif user_input and user_input[0] in known_hints:
|
||||||
|
self._hint_parser.parse_hints('hint-tester', self.HINTS_ALL, '<stdin>', [' '.join(user_input)])
|
||||||
|
self.write_excuses()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
readline.write_history_file(histfile)
|
readline.write_history_file(histfile)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
|
44
hints.py
44
hints.py
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
from itertools import chain
|
||||||
|
|
||||||
from migrationitem import MigrationItem
|
from migrationitem import MigrationItem
|
||||||
|
|
||||||
|
|
||||||
@ -178,6 +180,46 @@ class HintParser(object):
|
|||||||
'approve': 'unblock',
|
'approve': 'unblock',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def registered_hints(self):
|
||||||
|
"""A set of all known hints (and aliases thereof)"""
|
||||||
|
return set(chain(self._hint_table.keys(), self._aliases.keys()))
|
||||||
|
|
||||||
|
def register_hint_type(self, hint_name, parser_function, *, min_args=1, aliases=None):
|
||||||
|
"""Register a new hint that is supported by the parser
|
||||||
|
|
||||||
|
This registers a new hint that can be parsed by the hint parser. All hints are single words with a
|
||||||
|
space-separated list of arguments (on a single line). The hint parser will do some basic processing,
|
||||||
|
the permission checking and minor validation on the hint before passing it on to the parser function
|
||||||
|
given.
|
||||||
|
|
||||||
|
The parser_function will receive the following arguments:
|
||||||
|
* A hint collection
|
||||||
|
* Identifier of the entity providing the hint
|
||||||
|
* The hint_name (aliases will be mapped to the hint_name)
|
||||||
|
* Zero or more string arguments for the hint (so the function needs to use *args)
|
||||||
|
|
||||||
|
The parser_function will then have to process the arguments and call the hint collection's "add_hint"
|
||||||
|
as needed. Example implementations include "split_into_one_hint_per_package", which is used by almost
|
||||||
|
all policy hints.
|
||||||
|
|
||||||
|
:param hint_name: The name of the hint
|
||||||
|
:param parser_function: A function to add the hint
|
||||||
|
:param min_args: An optional positive integer (or 0) denoting the number of arguments the hint takes.
|
||||||
|
:param aliases: An optional iterable of aliases to the hint (use only for backwards compatibility)
|
||||||
|
"""
|
||||||
|
if min_args < 1:
|
||||||
|
raise ValueError("min_args must be at least 1")
|
||||||
|
if hint_name in self._hint_table:
|
||||||
|
raise ValueError("The hint type %s is already registered" % hint_name)
|
||||||
|
if hint_name in self._aliases:
|
||||||
|
raise ValueError("The hint type %s is already registered as an alias of %s" % (
|
||||||
|
hint_name, self._aliases[hint_name]))
|
||||||
|
self._hint_table[hint_name] = (min_args, parser_function)
|
||||||
|
if aliases:
|
||||||
|
for alias in aliases:
|
||||||
|
self._aliases[alias] = hint_name
|
||||||
|
|
||||||
def parse_hints(self, who, permitted_hints, filename, lines):
|
def parse_hints(self, who, permitted_hints, filename, lines):
|
||||||
hint_table = self._hint_table
|
hint_table = self._hint_table
|
||||||
line_no = 0
|
line_no = 0
|
||||||
@ -198,7 +240,7 @@ class HintParser(object):
|
|||||||
if hint_name not in hint_table:
|
if hint_name not in hint_table:
|
||||||
self.log("Unknown hint found in %s (line %d): '%s'" % (filename, line_no, line), type="W")
|
self.log("Unknown hint found in %s (line %d): '%s'" % (filename, line_no, line), type="W")
|
||||||
continue
|
continue
|
||||||
if hint_name not in permitted_hints:
|
if hint_name not in permitted_hints and 'ALL' not in permitted_hints:
|
||||||
reason = 'The hint is not a part of the permitted hints for ' + who
|
reason = 'The hint is not a part of the permitted hints for ' + who
|
||||||
self.log("Ignoring \"%s\" hint from %s found in %s (line %d): %s" % (
|
self.log("Ignoring \"%s\" hint from %s found in %s (line %d): %s" % (
|
||||||
hint_name, who, filename, line_no, reason), type="I")
|
hint_name, who, filename, line_no, reason), type="I")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user