#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Name: param_rewrite.py # Purpose: Provide functions to assist boot param rewriting with. # Authors: shinji-s # Licence: This file is a part of multibootusb package. You can redistribute # it or modify under the terms of GNU General Public License, v.2 or above from functools import partial # Operations def op_add_tokens(tokens, params): return params + [t for t in tokens if t not in params] def add_tokens(*tokens): return partial(op_add_tokens, tokens) def op_remove_tokens(tokens, params): return [x for x in params if x not in tokens] def remove_tokens(*tokens): return partial(op_remove_tokens, tokens) def op_replace_token(old_token, new_token, params): return [new_token if x==old_token else x for x in params] def replace_token(old_token, new_token): return partial(op_replace_token, old_token, new_token) def op_add_or_replace_kv(key, value, params): assert key.endswith('=') if any([x.startswith(key) for x in params]): return op_replace_kv(key, value, params) return params + [(key + (value(key, None, params) if callable(value) else value))] def add_or_replace_kv(key, value): assert key.endswith('=') return partial(op_add_or_replace_kv, key, value) def op_replace_kv(key, value, params): ''' Replace {value} of {key} if the key already exists in {params}. {value} may be a callable. In that case {value} will be called with key, definition to be replaced and {params}. ''' assert key.endswith('=') return [key + (value(key, x[len(key):], params) if callable(value) else value) if x.startswith(key) else x for x in params] def replace_kv(key, value): assert key.endswith('=') return partial(op_replace_kv, key, value) def op_remove_keys(keys, params): return [x for x in params if all([not x.startswith(k) for k in keys])] def remove_keys(*keys): assert all([k.endswith('=') for k in keys]) return partial(op_remove_keys, keys) # Predicates def always(starter_token, params): return True def contains_token(token): return lambda starter, params: token in params def contains_all_tokens(*tokens): return lambda starter, params: all([t in params for t in tokens]) def contains_any_token(*tokens): return lambda starter, params: any([t in params for t in tokens]) def contains_key(key): assert type(key)==str assert key[-1:] == '=' return lambda starter, params: any(x.startswith(key) for x in params) def contains_all_keys(*keys): assert all([k.endswith('=') for k in keys]) return lambda starter, params: all(any(p.startswith(k) for p in params) for k in keys) def contains_any_key(*keys): return lambda starter, params: any(any(p.startswith(k) for p in params) for k in keys) def starter_is_either(*possible_starters): return lambda starter, params: starter in possible_starters def _not(another_predicate): return lambda starter, params: not another_predicate(starter, params) def test_rewrite_machinary(): def transform(op_or_oplist, predicate, input_line): params = input_line.split(' ') if not predicate('test_starter', params): return input_line # See if op_or_oplist is iterable try: iter(op_or_oplist) except TypeError: # Otherwise let's assume we have a singleton op here op_or_oplist = [op_or_oplist] for op in op_or_oplist: params = op(params) return ' '.join(params) boot_line = "kernel /boot/vmlinuz bar=baz foo bar key2=value2" print ('Test token addition') assert transform(add_tokens('foo','more'), always, boot_line)==\ "kernel /boot/vmlinuz bar=baz foo bar key2=value2 more" print ('Test token replacement') assert transform(replace_token('foo', 'hum'), always, boot_line)==\ "kernel /boot/vmlinuz bar=baz hum bar key2=value2" print ('Test token removal') assert transform(remove_tokens('foo', 'bar'), always, boot_line)==\ "kernel /boot/vmlinuz bar=baz key2=value2" print ('Test kv add_or_replace (results in append)') assert transform(add_or_replace_kv('live-path=', '/lib/live'), always, boot_line)==\ "kernel /boot/vmlinuz bar=baz foo bar key2=value2 " \ "live-path=/lib/live" print ('Test kv add_or_replace (results in replace)') assert transform(add_or_replace_kv('bar=', '/lib/live'), always, boot_line)==\ "kernel /boot/vmlinuz bar=/lib/live foo bar key2=value2" print ('Test kv replace (results in no change)') assert transform(replace_kv('live-path=', '/lib/live'), always, boot_line)==\ "kernel /boot/vmlinuz bar=baz foo bar key2=value2" print ('Test kv replace (results in replace)') assert transform(replace_kv('bar=', '/lib/live'), always, boot_line)==\ "kernel /boot/vmlinuz bar=/lib/live foo bar key2=value2" print ('Test kv replace with computed value (bang! at head).') assert transform(replace_kv('bar=', lambda k, old_v, params: '!' + old_v), always, boot_line)==\ "kernel /boot/vmlinuz bar=!baz foo bar key2=value2" print ('Test key removal') assert transform(remove_keys('bar=','key2='), always, boot_line)==\ "kernel /boot/vmlinuz foo bar" print ('Test strip everything (multi-op)') assert transform([remove_tokens('foo', 'bar', 'kernel', '/boot/vmlinuz'), remove_keys('bar=', 'key2=')], always, boot_line)=='' print ('Test condition always') assert transform(replace_token('bar', 'tail'), always, boot_line)=="kernel /boot/vmlinuz bar=baz foo tail "\ "key2=value2" print ('Test condition contains_token (positive)') assert transform(replace_token('bar', 'tail'), contains_token('kernel'), boot_line)=="kernel /boot/vmlinuz bar=baz foo tail"\ " key2=value2" print ('Test condition contains_token (negative)') assert transform(replace_token('bar', 'tail'), contains_token('initrd'), boot_line)==boot_line print ('Test condition contains_all_tokens (positive)') assert transform(replace_token('bar', 'tail'), contains_all_tokens('kernel', 'foo'), boot_line)=="kernel /boot/vmlinuz bar=baz foo tail" \ " key2=value2" print ('Test condition contains_all_tokens (negative)') assert transform(replace_token('bar', 'tail'), contains_all_tokens('kernel', 'nowhere'), boot_line)==boot_line print ('Test condition contains_any_token (positive)') assert transform(replace_token('bar', 'tail'), contains_any_token('kernel', 'nowhere'), boot_line)=="kernel /boot/vmlinuz bar=baz foo tail" \ " key2=value2" print ('Test condition contains_any_token (negative)') assert transform(replace_token('bar', 'tail'), contains_any_token('not_anywhere', 'nowhere'), boot_line)==boot_line print ('Test condition contains_any_key (positive)') assert transform(replace_token('bar', 'tail'), contains_any_key('key2', 'nowhere'), boot_line)=="kernel /boot/vmlinuz bar=baz foo tail" \ " key2=value2" print ('Test condition contains_any_key (negative)') assert transform(replace_token('bar', 'tail'), contains_any_key('anywhere', 'else'), boot_line)==boot_line print ('Test not() predicate on contains_any_token (positive)') assert transform(replace_token('bar', 'tail'), _not(contains_any_token('nowhere', 'else')), boot_line)=="kernel /boot/vmlinuz bar=baz foo tail" \ " key2=value2" print ('Test not() predicate on contains_any_token (negative)') assert transform(replace_token('bar', 'tail'), _not(contains_any_token('nowhere', 'kernel')), boot_line)==boot_line print ('Test not() predicate on contains_all_keys (positive)') assert transform(replace_token('bar', 'tail'), _not(contains_all_keys('bar=', 'nonexistent_key=')), boot_line)=="kernel /boot/vmlinuz bar=baz foo tail" \ " key2=value2" print ('Test not() predicate on contains_all_keys (negative)') assert transform(replace_token('bar', 'tail'), _not(contains_all_keys('bar=', 'key2=')), boot_line)=="kernel /boot/vmlinuz bar=baz foo bar" \ " key2=value2"