mirror of
https://git.launchpad.net/~ubuntu-release/britney/+git/britney2-ubuntu
synced 2025-04-14 04:31:09 +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
25
britney.py
25
britney.py
@ -69,7 +69,7 @@ instead explained in the chapter "Excuses Generation".
|
||||
= Excuses =
|
||||
|
||||
An excuse is a detailed explanation of why a package can or cannot
|
||||
be updated in the testing distribution from a newer package in
|
||||
be updated in the testing distribution from a newer package in
|
||||
another distribution (like for example unstable). The main purpose
|
||||
of the excuses is to be written in an HTML file which will be
|
||||
published over HTTP. The maintainers will be able to parse it manually
|
||||
@ -259,9 +259,10 @@ class Britney(object):
|
||||
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_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):
|
||||
"""Class constructor
|
||||
@ -272,6 +273,7 @@ class Britney(object):
|
||||
|
||||
# parse the command line arguments
|
||||
self.policies = []
|
||||
self._hint_parser = HintParser(self)
|
||||
self.__parse_arguments()
|
||||
MigrationItem.set_architectures(self.options.architectures)
|
||||
|
||||
@ -281,7 +283,6 @@ class Britney(object):
|
||||
self.binaries = {}
|
||||
self.all_selected = []
|
||||
self.excuses = {}
|
||||
self._hint_parser = HintParser(self)
|
||||
|
||||
try:
|
||||
self.read_hints(self.options.hintsdir)
|
||||
@ -442,6 +443,7 @@ class Britney(object):
|
||||
# minimum days for unstable-testing transition and the list of hints
|
||||
# are handled as an ad-hoc case
|
||||
MINDAYS = {}
|
||||
|
||||
self.HINTS = {'command-line': self.HINTS_ALL}
|
||||
with open(self.options.config, encoding='utf-8') as config:
|
||||
for line in config:
|
||||
@ -2790,6 +2792,8 @@ class Britney(object):
|
||||
# so ensure readline does not split on these characters.
|
||||
readline.set_completer_delims(readline.get_completer_delims().replace('-', '').replace('/', ''))
|
||||
|
||||
known_hints = self._hint_parser.registered_hints
|
||||
|
||||
while True:
|
||||
# read the command from the command line
|
||||
try:
|
||||
@ -2803,19 +2807,18 @@ class Britney(object):
|
||||
# quit the hint tester
|
||||
if user_input and user_input[0] in ('quit', 'exit'):
|
||||
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'):
|
||||
try:
|
||||
self.do_hint(user_input[0], 'hint-tester',
|
||||
[k.rsplit("/", 1) for k in user_input[1:] if "/" in k])
|
||||
[k.rsplit("/", 1) for k in user_input[1:] if "/" in k])
|
||||
self.printuninstchange()
|
||||
except KeyboardInterrupt:
|
||||
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:
|
||||
readline.write_history_file(histfile)
|
||||
except IOError as e:
|
||||
|
44
hints.py
44
hints.py
@ -14,6 +14,8 @@
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from itertools import chain
|
||||
|
||||
from migrationitem import MigrationItem
|
||||
|
||||
|
||||
@ -178,6 +180,46 @@ class HintParser(object):
|
||||
'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):
|
||||
hint_table = self._hint_table
|
||||
line_no = 0
|
||||
@ -198,7 +240,7 @@ class HintParser(object):
|
||||
if hint_name not in hint_table:
|
||||
self.log("Unknown hint found in %s (line %d): '%s'" % (filename, line_no, line), type="W")
|
||||
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
|
||||
self.log("Ignoring \"%s\" hint from %s found in %s (line %d): %s" % (
|
||||
hint_name, who, filename, line_no, reason), type="I")
|
||||
|
Loading…
x
Reference in New Issue
Block a user