summaryrefslogtreecommitdiffstats
path: root/debian/uncrustify-trinity/uncrustify-trinity-0.74.0/scripts/gen_config_combinations_uniq_output.py
diff options
context:
space:
mode:
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.74.0/scripts/gen_config_combinations_uniq_output.py')
-rw-r--r--debian/uncrustify-trinity/uncrustify-trinity-0.74.0/scripts/gen_config_combinations_uniq_output.py493
1 files changed, 493 insertions, 0 deletions
diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.74.0/scripts/gen_config_combinations_uniq_output.py b/debian/uncrustify-trinity/uncrustify-trinity-0.74.0/scripts/gen_config_combinations_uniq_output.py
new file mode 100644
index 00000000..2fa4fb0c
--- /dev/null
+++ b/debian/uncrustify-trinity/uncrustify-trinity-0.74.0/scripts/gen_config_combinations_uniq_output.py
@@ -0,0 +1,493 @@
+from __future__ import print_function # python >= 2.6
+from os import makedirs, path, listdir, rename, remove
+from subprocess import Popen
+from filecmp import cmp
+from glob import iglob
+from shutil import rmtree
+from json import loads as json_loads, dump as json_dump
+from sys import stderr, argv, path as sys_path
+
+"""
+gen_config_combinations_uniq_output.py
+
+Creates from a given set of options all possible option settings
+combinations, formats files with those and displays how much non equal
+formatted outputs have been created.
+
+Expects arg1 to be a filepath to a json config file
+ (see config example below)
+
+:author: Daniel Chumak
+:license: GPL v2+
+"""
+
+
+# config = {
+# "option_settings": {
+# "AT_BOOL": ["False", "True"],
+# "AT_IARF": ["ignore", "add", "remove", "force"],
+# "AT_POS": ["ignore", "join", "lead", "lead_break", "lead_force",
+# "trail", "trail_break", "trail_force"],
+# "AT_LINE": ["auto", "lf", "crlf", "cr"],
+# "AT_NUM": [-2, -1, 0, 1, 2, 3],
+# "AT_UNUM": [0, 1, 2, 3]
+# },
+# "options": [{
+# "name": "nl_func_type_name",
+# "type": "AT_IARF"
+# }, {
+# "name": "nl_template_class",
+# "type": "AT_IARF"
+# }],
+# "out_dir": "./Out",
+# "in_files": ["./t.cpp", "./t2.cpp"],
+# "unc_bin": "../build/uncrustify",
+# "cleanup_lvl": 2,
+# "force_cleanup": false,
+# "json_output": false
+# }
+#
+
+
+def len_index_combinations(max_indices):
+ """generator function that yields a list starting from
+ n_0 = 0, ... n_m-1 = 0, n_m = 0
+ ...
+ n_0 = 0, ... n_m-1 = 0, n_m = n_m_max
+ ...
+ n_0 = 0, ... n_m-1 = 1, n_m = 0
+ n_0 = 0, ... n_m-1 = 1, n_m = 1
+ ...
+ n_0 = 0, ... n_m-1 = n_m-1_max, n_m = n_m_max
+ ...
+ n_0 = n_0_max, ... n_m-1 = n_m-1_max, n_m = n_m_max
+
+
+ :param max_indices: list of max values every position is going to reach
+
+ :yield: list of values at the current step
+ """
+
+ fields = len(max_indices)
+ accu = [0] * fields
+
+ # increment last position n, on max val move pos by one (n-1) and increment
+ # if (n-1) is max move again (n-2) and increment, ...
+ pos = fields
+ while pos >= 0:
+ yield (accu)
+
+ pos = fields - 1
+ accu[pos] += 1
+
+ # on reaching max reset value, move pos and increment at pos
+ while pos >= 0 and accu[pos] >= max_indices[pos]:
+ accu[pos] = 0
+ pos -= 1
+
+ if pos >= 0:
+ accu[pos] += 1
+
+
+def write_config_files(config):
+ """Writes a configuration file for each possible combination of 'option'
+ settings
+
+ :param config: configuration object, expects that it was processed by
+ check_config
+ """
+
+ options_len = len(config["options"])
+
+ # populate len_options with amount of settings for the types of each option
+ len_options = [0] * options_len
+ for i in range(options_len):
+ option_setting = config["options"][i]["type"]
+ len_options[i] = len(config["option_settings"][option_setting])
+
+ # write configuration files, one per possible combination
+ for combination in len_index_combinations(len_options):
+ len_indices = len(combination)
+
+ # generate output filepath
+ file_path = config['out_dir'] + "/"
+ for i in range(len_indices):
+ option_name = config["options"][i]["name"]
+ file_path += ("%s__" % option_name)
+ for i in range(len_indices):
+ option_type = config["options"][i]["type"]
+ option_setting = combination[i]
+ file_path += ("%d__" % option_setting)
+ file_path += "unc.cfg"
+
+ # write configuration file
+ with open(file_path, 'w') as f:
+ for i in range(len_indices):
+ option_name = config["options"][i]["name"]
+ option_type = config["options"][i]["type"]
+ option_setting = config["option_settings"][option_type][
+ combination[i]]
+
+ f.write("%s = %s\n" % (option_name, option_setting))
+
+
+def gen_equal_output_map(config):
+ """Formats 'in_files' with configs inside the 'out_dir' with Uncrustify and
+ groups formatted files with equal content together.
+ Expects config filename format generated by write_config_files
+
+ :param config: configuration object, expects that it was processed by
+ check_config
+ :return: dict of files with equal content
+ key -- group index
+ value -- filepath list
+ """
+
+ # maps that will hold configurations that produce the same formatted files
+ equal_output_map = {}
+ # map len counter
+ map_val_idx = 0
+
+ # iterate through all generated config file names
+
+ for cfg_path in sorted(iglob('%s/*.cfg' % config["out_dir"])):
+ for in_file_idx in range(len(config["in_files"])):
+ # extract substring form config gile name (removes __unc.cfg)
+ splits_file = cfg_path.split("__unc")
+ if len(splits_file) < 1:
+ raise Exception('split with "__unc" | Wrong split len: %d'
+ % len(splits_file))
+
+ out_path = ("%s__%d" % (splits_file[0], in_file_idx))
+
+ # gen formatted files with uncrustify binary
+ proc = Popen([config["unc_bin"],
+ "-c", cfg_path,
+ "-f", config["in_files"][in_file_idx],
+ "-o", out_path,
+ ])
+ proc.wait()
+ if proc.returncode != 0:
+ continue
+
+ # populate 'equal_output_map' map
+ if len(equal_output_map) == 0:
+ equal_output_map[0] = [out_path]
+ map_val_idx += 1
+ else:
+ found_flag = False
+ for i in range(map_val_idx):
+ # compare first file of group i with the generated file
+ if cmp(equal_output_map[i][0], out_path):
+ equal_output_map[i].append(out_path)
+ found_flag = True
+ break
+ # create new group if files do not match
+ if not found_flag:
+ equal_output_map[map_val_idx] = [out_path]
+ map_val_idx += 1
+
+ return equal_output_map
+
+
+def gen_output_dict(config, equal_output_map):
+ """Makes an output dict with the generated results.
+
+ :param config: configuration object, expects that it was processed by
+ check_config
+
+ :param equal_output_map: dict of files with equal content,
+ expects format generated by gen_equal_output_map
+ :return: output dict, format:
+ copies objects option_settings, options and in_files (renamed as
+ files) from the config object. Additionally has the object groups
+ that holds gourp - file - settings combination data
+ format:
+ groups = [ [fileIdx0[
+ [settingIdx0, settingIdx1, ...],
+ [settingIdx0, settingIdx1, ...] ] ]
+ [fileIdx1[
+ [settingIdx0, settingIdx1, ...],
+ [settingIdx0, settingIdx1, ...] ] ]
+ ]
+ """
+
+ output_dict = {"option_settings": config["option_settings"],
+ "options": config["options"],
+ "files": config["in_files"],
+ "groups": []}
+
+ options_len = len(output_dict["options"])
+ files_len = len(output_dict["files"])
+
+ for key in equal_output_map:
+ group_dict = []
+ for file_arr_idx in range(files_len):
+ group_dict.append([])
+
+ for list_value in equal_output_map[key]:
+ split = list_value.rsplit("/", 1)
+ split = split[len(split) - 1].split("__")
+ split_len = len(split)
+
+ # n option names + n option values + file idx
+ if split_len < options_len * 2 + 1:
+ print(" wrong split len on %s\n" % list_value, file=stderr)
+ continue
+
+ file_idx = int(split[split_len - 1])
+ file_combinations = [int(i) for i in split[options_len:split_len-1]]
+
+ group_dict[file_idx].append(file_combinations)
+
+ output_dict["groups"].append(group_dict)
+
+ return output_dict
+
+
+def write_output_dict_pretty(out_dict, out_path):
+ """pretty prints the output dict into a file
+
+ :param out_dict: dict that will be printed, expects format generated by
+ gen_output_dict
+
+ :param out_path: output filepath
+ """
+
+ group_id = 0
+ options_len = len(out_dict["options"])
+
+ with open(out_path, 'w') as f:
+
+ f.write("Files:\n")
+ for in_file_idx in range(len(out_dict["files"])):
+ f.write(" %d: %s\n" % (in_file_idx,
+ out_dict["files"][in_file_idx]))
+
+ f.write("\nOptions:\n")
+ for option_idx in range(options_len):
+ f.write(" %d: %s\n" % (option_idx,
+ out_dict["options"][option_idx]["name"]))
+ f.write("\n\n")
+
+ for group in out_dict["groups"]:
+ f.write("Group: %d\n" % group_id)
+ group_id += 1
+
+ for file_idx in range(len(group)):
+ file = group[file_idx]
+
+ for combinations in file:
+ combination_strings = []
+ for combination_idx in range(len(combinations)):
+
+ combination_id = combinations[combination_idx]
+ combination_string = out_dict["option_settings"][
+ out_dict["options"][combination_idx]["type"]][
+ combination_id]
+ combination_strings.append(str(combination_string))
+ f.write(" (%s: %s)\n" % (file_idx,
+ " - ".join(combination_strings)))
+ f.write("\n")
+
+
+def load_config(file_path):
+ """reads a file and parses it as json
+
+ :param file_path: path to the json file
+
+ :return: json object
+ """
+
+ with open(file_path, 'r') as f:
+ string = f.read()
+ json = json_loads(string)
+
+ return json
+
+
+def make_abs_path(basis_abs_path, rel_path):
+ return path.normpath(path.join(basis_abs_path, rel_path))
+
+
+def check_config(config, cfg_path=""):
+ """checks if the provided config has all needed options, sets default
+ settings for optional options and transform relative paths into absolute
+ paths.
+
+ :param config: config dict that will be checked
+
+ :param cfg_path: if not empty transforms relative to absolute paths,
+ paths will be based upon the cfg_path.
+ """
+
+ extend_relative_paths = True if len(cfg_path) > 0 else False
+ cfg_path = path.abspath(path.dirname(cfg_path))
+
+ # --------------------------------------------------------------------------
+
+ if "option_settings" not in config:
+ raise Exception("config file: 'option_settings' missing")
+
+ if len(config["option_settings"]) == 0:
+ raise Exception("config file: 'option_settings' values missing")
+
+ # --------------------------------------------------------------------------
+
+ if "options" not in config:
+ raise Exception("config file: 'options' missing")
+
+ if len(config["options"]) < 2:
+ raise Exception("config file: 'options' min. two options needed")
+
+ for option_obj in config["options"]:
+ if "name" not in option_obj:
+ raise Exception("config file: 'options[{}]' name missing")
+ if "type" not in option_obj:
+ raise Exception("config file: 'options[{}]' type missing")
+ if option_obj["type"] not in config["option_settings"]:
+ raise Exception("config file: 'options[{type='%s'}]' not in option_"
+ "settings" % option_obj["type"])
+
+ # --------------------------------------------------------------------------
+
+ if "out_dir" not in config:
+ raise Exception("config file: 'out_dir' missing")
+
+ if len(config['out_dir']) == 0:
+ raise Exception("config file: 'out_dir' value missing")
+
+ if extend_relative_paths and not path.isabs(config['out_dir']):
+ config['out_dir'] = make_abs_path(cfg_path, config['out_dir'])
+
+ # --------------------------------------------------------------------------
+
+ if "in_files" not in config:
+ raise Exception("config file: 'in_files' missing")
+
+ if len(config['in_files']) == 0:
+ raise Exception("config file: 'in_files' values missing")
+
+ for file_idx in range(len(config['in_files'])):
+ if extend_relative_paths and not path.isabs(
+ config['in_files'][file_idx]):
+ config['in_files'][file_idx] = make_abs_path(cfg_path,
+ config['in_files'][
+ file_idx])
+
+ if not path.isfile(config['in_files'][file_idx]):
+ raise Exception("config file: '%s' is not a file"
+ % config['in_files'][file_idx])
+
+ # --------------------------------------------------------------------------
+
+ if "unc_bin" not in config:
+ raise Exception("config file: 'in_files' missing")
+
+ if extend_relative_paths and not path.isabs(config['unc_bin']):
+ config['unc_bin'] = make_abs_path(cfg_path, config['unc_bin'])
+
+ if not path.isfile(config['unc_bin']):
+ raise Exception("config file: '%s' is not a file" % config['unc_bin'])
+
+ # Optional -----------------------------------------------------------------
+
+ if "cleanup_lvl" not in config:
+ config["cleanup_lvl"] = 1
+
+ if "force_cleanup" not in config:
+ config["force_cleanup"] = False
+
+ if "json_output" not in config:
+ config["json_output"] = False
+
+
+def cleanup(level, eq_map, clean_target_dir, keep_files=()):
+ """cleans up output_dir
+
+ :param level: 0 - do nothing,
+ 1 - keep `keep_files` and 1 file for each group,
+ 2 - remove everything
+
+ :param equal_output_map: dict of files with equal content,
+ expects format generated by gen_equal_output_map
+
+ :param clean_target_dir: directory which content will be cleaned
+
+ :param keep_files: list of files should not be removed
+ """
+
+ if level == 0:
+ return
+
+ if level == 2:
+ rmtree(clean_target_dir)
+
+ if level == 1:
+ rm_files = [clean_target_dir + "/" + f for f in
+ listdir(clean_target_dir)]
+
+ for f in keep_files:
+ rm_files.remove(f)
+
+ for idx in eq_map:
+ old_path = eq_map[idx][0]
+ new_path = ("%s/g_%d" % (path.dirname(path.abspath(old_path)), idx))
+ rename(old_path, new_path)
+
+ try:
+ rm_files.remove(old_path)
+ except ValueError:
+ pass # ignore that it is missing
+
+ try:
+ rm_files.remove(new_path)
+ except ValueError:
+ pass # ignore that it is missing
+
+ for f in rm_files:
+ remove(f)
+
+
+def main(args):
+ config = load_config(args[0])
+ check_config(config, args[0])
+
+ # gen output directory
+ if path.isfile(config["out_dir"]):
+ raise Exception("%s is a file" % config["out_dir"])
+
+ if not path.isdir(config["out_dir"]):
+ makedirs(config["out_dir"])
+ elif not config["force_cleanup"] and config["cleanup_lvl"] > 0:
+ raise Exception("cleanup_lvl > 0 on an existing directory: %s"
+ % config["out_dir"])
+
+ write_config_files(config)
+ eq_map = gen_equal_output_map(config)
+ output_dict = gen_output_dict(config, eq_map)
+
+ # write output as txt file
+ output_dict_path = path.join(config["out_dir"], "out.txt")
+ write_output_dict_pretty(output_dict, output_dict_path)
+
+ # read ouput txt file to print it
+ with open(output_dict_path, 'r') as f:
+ print()
+ print(f.read())
+
+ keep_files = [output_dict_path]
+
+ # write output as json file
+ if config["json_output"]:
+ output_dict_json_path = path.join(config["out_dir"], "out.json")
+ with open(output_dict_json_path, 'w') as f:
+ json_dump(output_dict, f)
+ keep_files.append(output_dict_json_path)
+
+ # clean output directory
+ cleanup(config["cleanup_lvl"], eq_map, config["out_dir"], keep_files)
+
+
+if __name__ == "__main__":
+ main(argv[1:])