#!/usr/bin/python3
import sys
import os
import argparse
import json
import ssg.rules
import ssg.utils
import ssg.rule_yaml
SSG_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
[docs]
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("-j", "--json", type=str, action="store", default="build/rule_dirs.json",
help="File to read json output of rule_dir_json from (defaults "
"to build/rule_dirs.json)")
parser.add_argument("rule_id", type=str, help="Rule to change, by id")
parser.add_argument("action", choices=['add', 'remove', 'list', 'replace'],
help="Rule to change, by id")
parser.add_argument("products", type=str, nargs='*',
help="Products to perform action with on rule_id. For replace, "
"the expected format is "
"product[,other_product]~product[,other_product] "
"where the first half is the products that are required to "
"match, and are replaced by the products in the second half "
"if all match.")
return parser.parse_args()
[docs]
def list_products(rule_obj):
yaml_file, yaml_contents = ssg.rule_yaml.get_yaml_contents(rule_obj)
prodtype_section = ssg.rule_yaml.get_section_lines(yaml_file, yaml_contents, 'prodtype')
print("Computed products:")
for product in sorted(rule_obj.get('products', [])):
print(" - %s" % product)
print("")
if prodtype_section:
prodtype_contents = ssg.rule_yaml.parse_from_yaml(yaml_contents, prodtype_section)
prodtype = ssg.rule_yaml.parse_prodtype(prodtype_contents['prodtype'])
print("Listed products:")
for product in prodtype:
print(" - %s" % product)
else:
print("Empty listed prodtype in the file")
[docs]
def add_products(rule_obj, products, silent=False):
yaml_file, yaml_contents = ssg.rule_yaml.get_yaml_contents(rule_obj)
prodtype_section = ssg.rule_yaml.get_section_lines(yaml_file, yaml_contents, 'prodtype')
if not prodtype_section:
new_prodtype = sorted(set(products))
new_prodtype_str = ','.join(new_prodtype)
doc_complete_section = ssg.rule_yaml.get_section_lines(yaml_file, yaml_contents,
'documentation_complete')
if not doc_complete_section:
print("Cannot modify empty prodtype with missing documentation_complete... "
"Are you sure this is a rule file? %s" % yaml_file, file=sys.stderr)
sys.exit(1)
start_line = doc_complete_section[1]+1
if not silent:
print("Current prodtype is empty, not adding the new prodtype.")
else:
prodtype_contents = ssg.rule_yaml.parse_from_yaml(yaml_contents, prodtype_section)
prodtype = prodtype_contents['prodtype']
new_prodtype = ssg.rule_yaml.parse_prodtype(prodtype)
new_prodtype.update(products)
new_prodtype_str = ','.join(sorted(new_prodtype))
print("Modifying %s:" % yaml_file)
print(" Current prodtype: %s" % prodtype)
print(" New prodtype: %s" % new_prodtype_str)
yaml_contents = ssg.rule_yaml.update_key_value(yaml_contents, 'prodtype',
prodtype, new_prodtype_str)
ssg.utils.write_list_file(yaml_file, yaml_contents)
[docs]
def remove_products(rule_obj, products):
yaml_file, yaml_contents = ssg.rule_yaml.get_yaml_contents(rule_obj)
prodtype_section = ssg.rule_yaml.get_section_lines(yaml_file, yaml_contents, 'prodtype')
if not prodtype_section:
print("Cannot modify empty prodtype to remove products from %s" %
yaml_file, file=sys.stderr)
sys.exit(1)
prodtype_contents = ssg.rule_yaml.parse_from_yaml(yaml_contents, prodtype_section)
prodtype = prodtype_contents['prodtype']
new_prodtype = ssg.rule_yaml.parse_prodtype(prodtype)
new_prodtype = new_prodtype.difference(products)
new_prodtype_str = ','.join(sorted(new_prodtype))
print("Current prodtype: %s" % prodtype)
if new_prodtype:
print("New prodtype: %s" % new_prodtype_str)
yaml_contents = ssg.rule_yaml.update_key_value(yaml_contents, 'prodtype',
prodtype, new_prodtype_str)
else:
print("New prodtype is empty")
yaml_contents = ssg.rule_yaml.remove_lines(yaml_contents, prodtype_section)
ssg.utils.write_list_file(yaml_file, yaml_contents)
[docs]
def replace_products(rule_obj, products):
yaml_file, yaml_contents = ssg.rule_yaml.get_yaml_contents(rule_obj)
prodtype_section = ssg.rule_yaml.get_section_lines(yaml_file, yaml_contents, 'prodtype')
if not prodtype_section:
print("Cannot modify empty prodtype to replace products from %s" % yaml_file,
file=sys.stderr)
sys.exit(1)
parsed_changes = []
for product in products:
parsed_product = product.split('~')
if not len(parsed_product) == 2:
print("Invalid product replacement description: %s" % product,
file=sys.stderr)
sys.exit(1)
change = {
'match': ssg.rule_yaml.parse_prodtype(parsed_product[0]),
'replacement': ssg.rule_yaml.parse_prodtype(parsed_product[1]),
}
parsed_changes.append(change)
prodtype_contents = ssg.rule_yaml.parse_from_yaml(yaml_contents, prodtype_section)
prodtype = prodtype_contents['prodtype']
current_prodtypes = ssg.rule_yaml.parse_prodtype(prodtype)
new_prodtypes = set(current_prodtypes)
for change in parsed_changes:
if change['match'].issubset(current_prodtypes):
new_prodtypes.difference_update(change['match'])
new_prodtypes.update(change['replacement'])
new_prodtype_str = ','.join(sorted(new_prodtypes))
print("Current prodtype: %s" % prodtype)
print("New prodtype: %s" % new_prodtype_str)
yaml_contents = ssg.rule_yaml.update_key_value(yaml_contents, 'prodtype',
prodtype, new_prodtype_str)
ssg.utils.write_list_file(yaml_file, yaml_contents)
[docs]
def main():
args = parse_args()
json_file = open(args.json, 'r')
known_rules = json.load(json_file)
if args.rule_id not in known_rules:
print("Error: rule_id:%s is not known!" % args.rule_id, file=sys.stderr)
print("If you think this is an error, try regenerating the JSON.", file=sys.stderr)
sys.exit(1)
if args.action != "list" and not args.products:
print("Error: expected a list of products or replace transformations but "
"none given.", file=sys.stderr)
sys.exit(1)
rule_obj = known_rules[args.rule_id]
print("rule_id:%s\n" % args.rule_id)
if args.action == "list":
list_products(rule_obj)
elif args.action == "add":
add_products(rule_obj, args.products)
elif args.action == "remove":
remove_products(rule_obj, args.products)
elif args.action == "replace":
replace_products(rule_obj, args.products)
else:
print("Unknown option: %s" % args.action)
if __name__ == "__main__":
main()