| Total Complexity | 52 |
| Total Lines | 342 |
| Duplicated Lines | 53.51 % |
| Coverage | 0% |
| Changes | 0 | ||
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like rule_dir_diff often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | #!/usr/bin/env python |
||
| 2 | |||
| 3 | from __future__ import print_function |
||
| 4 | |||
| 5 | import argparse |
||
| 6 | import os |
||
| 7 | import sys |
||
| 8 | |||
| 9 | import json |
||
| 10 | import pprint |
||
| 11 | |||
| 12 | import ssg.build_yaml |
||
| 13 | import ssg.oval |
||
| 14 | import ssg.build_remediations |
||
| 15 | import ssg.rule_dir_stats as rds |
||
| 16 | import ssg.rules |
||
| 17 | import ssg.yaml |
||
| 18 | |||
| 19 | |||
| 20 | SSG_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) |
||
| 21 | |||
| 22 | |||
| 23 | def parse_args(): |
||
| 24 | parser = argparse.ArgumentParser() |
||
| 25 | parser.add_argument("--left", type=str, action="store", default="build/old_rule_dirs.json", |
||
| 26 | help="File to read json output of rule_dir_json from (defaults to " + |
||
| 27 | "build/old_rule_dirs.json); left such file for diffing") |
||
| 28 | parser.add_argument("--right", type=str, action="store", default="build/rule_dirs.json", |
||
| 29 | help="File to read json output of rule_dir_json from (defaults to " + |
||
| 30 | "build/rule_dirs.json); right such file for diffing") |
||
| 31 | |||
| 32 | parser.add_argument("-p", "--products", type=str, action="store", default="all", |
||
| 33 | help="Products to inquire about, as a comma separated list") |
||
| 34 | parser.add_argument("-t", "--strict", action="store_true", |
||
| 35 | help="Enforce strict --products checking against rule.yml prodtype only") |
||
| 36 | parser.add_argument("-q", "--query", type=str, action="store", default=None, |
||
| 37 | help="Limit actions to only act on a comma separated list of rule_ids") |
||
| 38 | |||
| 39 | parser.add_argument("-m", "--missing", action="store_true", |
||
| 40 | help="List rules which are missing OVALs or fixes") |
||
| 41 | parser.add_argument("-2", "--two-plus", action="store_true", |
||
| 42 | help="List rules which have two or more OVALs or fixes") |
||
| 43 | parser.add_argument("-r", "--prodtypes", action="store_true", |
||
| 44 | help="List rules which have different YAML prodtypes from checks+fix prodtypes") |
||
| 45 | parser.add_argument("-n", "--product-names", action="store_true", |
||
| 46 | help="List rules which have product specific objects with broader accepted products") |
||
| 47 | |||
| 48 | parser.add_argument("-o", "--ovals-only", action="store_true", |
||
| 49 | help="Only output information about OVALs") |
||
| 50 | parser.add_argument("-f", "--fixes-only", action="store_true", |
||
| 51 | help="Only output information about fixes") |
||
| 52 | |||
| 53 | parser.add_argument("--left-only", action="store_true", |
||
| 54 | help="Print only information from the left that is " + |
||
| 55 | "not in the right") |
||
| 56 | parser.add_argument("--right-only", action="store_true", |
||
| 57 | help="Print only information from the right that is " + |
||
| 58 | "not in the left") |
||
| 59 | parser.add_argument("--show-common", action="store_true", |
||
| 60 | help="Also print information that is common to both") |
||
| 61 | |||
| 62 | parser.add_argument("-s", "--summary-only", action="store_true", |
||
| 63 | help="Only output summary information") |
||
| 64 | |||
| 65 | return parser.parse_args() |
||
| 66 | |||
| 67 | |||
| 68 | def prefixed_print(statement, prefix): |
||
| 69 | print("%s %s" % (prefix, statement)) |
||
| 70 | |||
| 71 | |||
| 72 | def print_specifics(args, headline, data, prefix): |
||
| 73 | if not args.summary_only and data: |
||
| 74 | prefixed_print(headline, prefix) |
||
| 75 | for line in data: |
||
| 76 | prefixed_print(line, prefix) |
||
| 77 | print("\n") |
||
| 78 | |||
| 79 | |||
| 80 | def print_summary(args, statements, data, prefix): |
||
| 81 | affected_rules, affected_ovals, affected_remediations, affected_remediations_type = data |
||
| 82 | |||
| 83 | prefixed_print(statements[0], prefix) |
||
| 84 | prefixed_print(statements[1] % affected_rules, prefix) |
||
| 85 | if not args.fixes_only: |
||
| 86 | prefixed_print(statements[2] % (affected_ovals, affected_rules), prefix) |
||
| 87 | if not args.ovals_only: |
||
| 88 | prefixed_print(statements[3] % (affected_remediations, affected_rules), prefix) |
||
| 89 | for r_type in ssg.build_remediations.REMEDIATION_TO_EXT_MAP: |
||
| 90 | r_missing = affected_remediations_type[r_type] |
||
| 91 | prefixed_print(statements[4] % (r_type, r_missing, affected_rules), prefix) |
||
| 92 | print("\n") |
||
| 93 | |||
| 94 | |||
| 95 | def select_indices(data, indices): |
||
| 96 | return [data[index] for index in indices] |
||
| 97 | |||
| 98 | |||
| 99 | View Code Duplication | def process_diff_missing(args, left_rules, right_rules): |
|
|
|
|||
| 100 | data = rds.walk_rules_diff(args, left_rules, right_rules, rds.missing_oval, rds.missing_remediation) |
||
| 101 | result = rds.walk_rules_diff_stats(data) |
||
| 102 | left_only_data, right_only_data, left_changed_data, right_changed_data, common_data = result |
||
| 103 | |||
| 104 | statements = ["Missing Objects Summary", |
||
| 105 | "Total affected rules: %d", |
||
| 106 | "Rules with no OVALs: %d / %d", |
||
| 107 | "Rules without any remediations: %d / %d", |
||
| 108 | "Rules with no %s remediations: %d / %d"] |
||
| 109 | |||
| 110 | if not args.right_only: |
||
| 111 | print_specifics(args, "Missing Objects Specifics - Left Only:", left_only_data[5], '<') |
||
| 112 | print_specifics(args, "Missing Objects Specifics - Left Changed:", left_changed_data[5], '<') |
||
| 113 | |||
| 114 | if args.show_common: |
||
| 115 | print_specifics(args, "Missing Objects Specifics - Common:", common_data[5], '=') |
||
| 116 | |||
| 117 | if not args.left_only: |
||
| 118 | print_specifics(args, "Missing Objects Specifics - Right Changed:", right_changed_data[5], '>') |
||
| 119 | print_specifics(args, "Missing Objects Specifics - Right Only:", right_only_data[5], '>') |
||
| 120 | |||
| 121 | data_indices = [0, 1, 3, 4] |
||
| 122 | |||
| 123 | if not args.right_only: |
||
| 124 | statements[0] = "Missing Objects Summary - Left Only:" |
||
| 125 | l_d = select_indices(left_only_data, data_indices) |
||
| 126 | print_summary(args, statements, l_d, '<') |
||
| 127 | |||
| 128 | statements[0] = "Missing Objects Summary - Left Changed:" |
||
| 129 | l_d = select_indices(left_changed_data, data_indices) |
||
| 130 | print_summary(args, statements, l_d, '<') |
||
| 131 | |||
| 132 | if args.show_common: |
||
| 133 | statements[0] = "Missing Objects Summary - Common:" |
||
| 134 | c_d = select_indices(common_data, data_indices) |
||
| 135 | print_summary(args, statements, c_d, '=') |
||
| 136 | |||
| 137 | if not args.left_only: |
||
| 138 | statements[0] = "Missing Objects Summary - Right Changed:" |
||
| 139 | r_d = select_indices(right_changed_data, data_indices) |
||
| 140 | print_summary(args, statements, r_d, '>') |
||
| 141 | |||
| 142 | statements[0] = "Missing Objects Summary - Right Only:" |
||
| 143 | r_d = select_indices(right_only_data, data_indices) |
||
| 144 | print_summary(args, statements, r_d, '>') |
||
| 145 | |||
| 146 | |||
| 147 | View Code Duplication | def process_diff_two_plus(args, left_rules, right_rules): |
|
| 148 | data = rds.walk_rules_diff(args, left_rules, right_rules, rds.two_plus_oval, rds.two_plus_remediation) |
||
| 149 | result = rds.walk_rules_diff_stats(data) |
||
| 150 | left_only_data, right_only_data, left_changed_data, right_changed_data, common_data = result |
||
| 151 | |||
| 152 | statements = ["Two Plus Objects Summary:", |
||
| 153 | "Total affected rules: %d", |
||
| 154 | "Rules with two or more OVALs: %d / %d", |
||
| 155 | "Rules with two or more remediations: %d / %d", |
||
| 156 | "Rules with two or more %s remediations: %d / %d"] |
||
| 157 | |||
| 158 | if not args.right_only: |
||
| 159 | print_specifics(args, "Two Plus Objects Specifics - Left Only:", left_only_data[5], '<') |
||
| 160 | print_specifics(args, "Two Plus Objects Specifics - Left Changed:", left_changed_data[5], '<') |
||
| 161 | |||
| 162 | if args.show_common: |
||
| 163 | print_specifics(args, "Two Plus Objects Specifics - Common:", common_data[5], '=') |
||
| 164 | |||
| 165 | if not args.left_only: |
||
| 166 | print_specifics(args, "Two Plus Objects Specifics - Right Changed:", right_changed_data[5], '>') |
||
| 167 | print_specifics(args, "Two Plus Objects Specifics - Right Only:", right_only_data[5], '>') |
||
| 168 | |||
| 169 | data_indices = [0, 1, 2, 4] |
||
| 170 | |||
| 171 | if not args.right_only: |
||
| 172 | statements[0] = "Two Plus Objects Summary - Left Only:" |
||
| 173 | l_d = select_indices(left_only_data, data_indices) |
||
| 174 | print_summary(args, statements, l_d, '<') |
||
| 175 | |||
| 176 | statements[0] = "Two Plus Objects Summary - Left Changed:" |
||
| 177 | l_d = select_indices(left_changed_data, data_indices) |
||
| 178 | print_summary(args, statements, l_d, '<') |
||
| 179 | |||
| 180 | if args.show_common: |
||
| 181 | statements[0] = "Two Plus Objects Summary - Common:" |
||
| 182 | c_d = select_indices(common_data, data_indices) |
||
| 183 | print_summary(args, statements, c_d, '=') |
||
| 184 | |||
| 185 | if not args.left_only: |
||
| 186 | statements[0] = "Two Plus Objects Summary - Right Changed:" |
||
| 187 | r_d = select_indices(right_changed_data, data_indices) |
||
| 188 | print_summary(args, statements, r_d, '>') |
||
| 189 | |||
| 190 | statements[0] = "Two Plus Objects Summary - Right Only:" |
||
| 191 | r_d = select_indices(right_only_data, data_indices) |
||
| 192 | print_summary(args, statements, r_d, '>') |
||
| 193 | |||
| 194 | |||
| 195 | View Code Duplication | def process_diff_prodtypes(args, left_rules, right_rules): |
|
| 196 | data = rds.walk_rules_diff(args, left_rules, right_rules, rds.prodtypes_oval, rds.prodtypes_remediation) |
||
| 197 | result = rds.walk_rules_diff_stats(data) |
||
| 198 | left_only_data, right_only_data, left_changed_data, right_changed_data, common_data = result |
||
| 199 | |||
| 200 | statements = ["Prodtypes Objects Summary", |
||
| 201 | "Total affected rules: %d", |
||
| 202 | "Rules with differing prodtypes between YAML and OVALs: %d / %d", |
||
| 203 | "Rules with differing prodtypes between YAML and remediations: %d / %d", |
||
| 204 | "Rules with differing prodtypes between YAML and %s remediations: %d / %d"] |
||
| 205 | |||
| 206 | if not args.right_only: |
||
| 207 | print_specifics(args, "Prodtypes Objects Specifics - Left Only:", left_only_data[5], '<') |
||
| 208 | print_specifics(args, "Prodtypes Objects Specifics - Left Changed:", left_changed_data[5], '<') |
||
| 209 | |||
| 210 | if args.show_common: |
||
| 211 | print_specifics(args, "Prodtypes Objects Specifics - Common:", common_data[5], '=') |
||
| 212 | |||
| 213 | if not args.left_only: |
||
| 214 | print_specifics(args, "Prodtypes Objects Specifics - Right Changed:", right_changed_data[5], '>') |
||
| 215 | print_specifics(args, "Prodtypes Objects Specifics - Right Only:", right_only_data[5], '>') |
||
| 216 | |||
| 217 | data_indices = [0, 1, 2, 4] |
||
| 218 | |||
| 219 | if not args.right_only: |
||
| 220 | statements[0] = "Prodtypes Objects Summary - Left Only:" |
||
| 221 | l_d = select_indices(left_only_data, data_indices) |
||
| 222 | print_summary(args, statements, l_d, '<') |
||
| 223 | |||
| 224 | statements[0] = "Prodtypes Objects Summary - Left Changed:" |
||
| 225 | l_d = select_indices(left_changed_data, data_indices) |
||
| 226 | print_summary(args, statements, l_d, '<') |
||
| 227 | |||
| 228 | if args.show_common: |
||
| 229 | statements[0] = "Prodtypes Objects Summary - Common:" |
||
| 230 | c_d = select_indices(common_data, data_indices) |
||
| 231 | print_summary(args, statements, c_d, '=') |
||
| 232 | |||
| 233 | if not args.left_only: |
||
| 234 | statements[0] = "Prodtypes Objects Summary - Right Changed:" |
||
| 235 | r_d = select_indices(right_changed_data, data_indices) |
||
| 236 | print_summary(args, statements, r_d, '>') |
||
| 237 | |||
| 238 | statements[0] = "Prodtypes Objects Summary - Right Only:" |
||
| 239 | r_d = select_indices(right_only_data, data_indices) |
||
| 240 | print_summary(args, statements, r_d, '>') |
||
| 241 | |||
| 242 | |||
| 243 | View Code Duplication | def process_diff_product_names(args, left_rules, right_rules): |
|
| 244 | data = rds.walk_rules_diff(args, left_rules, right_rules, rds.product_names_oval, rds.product_names_remediation) |
||
| 245 | result = rds.walk_rules_diff_stats(data) |
||
| 246 | left_only_data, right_only_data, left_changed_data, right_changed_data, common_data = result |
||
| 247 | |||
| 248 | if not args.right_only: |
||
| 249 | print_specifics(args, "Product Names Objects Specifics - Left Only:", left_only_data[5], '<') |
||
| 250 | print_specifics(args, "Product Names Objects Specifics - Left Changed:", left_changed_data[5], '<') |
||
| 251 | |||
| 252 | if args.show_common: |
||
| 253 | print_specifics(args, "Product Names Objects Specifics - Common:", common_data[5], '=') |
||
| 254 | |||
| 255 | if not args.left_only: |
||
| 256 | print_specifics(args, "Product Names Objects Specifics - Right Changed:", right_changed_data[5], '>') |
||
| 257 | print_specifics(args, "Product Names Objects Specifics - Right Only:", right_only_data[5], '>') |
||
| 258 | |||
| 259 | data_indices = [0, 1, 2, 4] |
||
| 260 | statements = ["Product Names Objects Summary:", |
||
| 261 | "Total affected rules: %d", |
||
| 262 | "Rules with differing products and OVAL names: %d / %d", |
||
| 263 | "Rules with differing product and remediation names: %d / %d", |
||
| 264 | "Rules with differing product and %s remediation names: %d / %d"] |
||
| 265 | |||
| 266 | if not args.right_only: |
||
| 267 | statements[0] = "Product Names Objects Summary - Left Only:" |
||
| 268 | l_d = select_indices(left_only_data, data_indices) |
||
| 269 | print_summary(args, statements, l_d, '<') |
||
| 270 | |||
| 271 | statements[0] = "Product Names Objects Summary - Left Changed:" |
||
| 272 | l_d = select_indices(left_changed_data, data_indices) |
||
| 273 | print_summary(args, statements, l_d, '<') |
||
| 274 | |||
| 275 | if args.show_common: |
||
| 276 | statements[0] = "Product Names Objects Summary - Common:" |
||
| 277 | c_d = select_indices(common_data, data_indices) |
||
| 278 | print_summary(args, statements, c_d, '=') |
||
| 279 | |||
| 280 | if not args.left_only: |
||
| 281 | statements[0] = "Product Names Objects Summary - Right Changed:" |
||
| 282 | r_d = select_indices(right_changed_data, data_indices) |
||
| 283 | print_summary(args, statements, r_d, '>') |
||
| 284 | |||
| 285 | statements[0] = "Product Names Objects Summary - Right Only:" |
||
| 286 | r_d = select_indices(right_only_data, data_indices) |
||
| 287 | print_summary(args, statements, r_d, '>') |
||
| 288 | |||
| 289 | |||
| 290 | def main(): |
||
| 291 | args = parse_args() |
||
| 292 | |||
| 293 | linux_products, other_products = ssg.products.get_all(SSG_ROOT) |
||
| 294 | all_products = linux_products.union(other_products) |
||
| 295 | |||
| 296 | left_file = open(args.left, 'r') |
||
| 297 | left_rules = json.load(left_file) |
||
| 298 | |||
| 299 | right_file = open(args.right, 'r') |
||
| 300 | right_rules = json.load(right_file) |
||
| 301 | |||
| 302 | if left_rules == right_rules: |
||
| 303 | print("No difference. Please use rule_dir_stats to inspect one of these files.") |
||
| 304 | sys.exit(0) |
||
| 305 | |||
| 306 | if args.products.lower() == 'all': |
||
| 307 | args.products = all_products |
||
| 308 | elif args.products.lower() == 'linux': |
||
| 309 | args.products = linux_products |
||
| 310 | elif args.products.lower() == 'other': |
||
| 311 | args.products = other_products |
||
| 312 | else: |
||
| 313 | args.products = args.products.split(',') |
||
| 314 | args.products = set(args.products) |
||
| 315 | |||
| 316 | left_query_keys = rds.filter_rule_ids(set(left_rules), args.query) |
||
| 317 | right_query_keys = rds.filter_rule_ids(set(right_rules), args.query) |
||
| 318 | args.query = left_query_keys.union(right_query_keys) |
||
| 319 | print("Total number of queried rules: %d\n" % len(args.query)) |
||
| 320 | |||
| 321 | if not args.missing and not args.two_plus and not args.prodtypes and not args.product_names: |
||
| 322 | args.missing = True |
||
| 323 | args.two_plus = True |
||
| 324 | args.prodtypes = True |
||
| 325 | |||
| 326 | print("< Total number of known rule directories: %d" % len(left_rules)) |
||
| 327 | print("> Total number of known rule directories: %d\n" % len(right_rules)) |
||
| 328 | print("= Total number of queried rules: %d\n" % len(args.query)) |
||
| 329 | |||
| 330 | if args.missing: |
||
| 331 | process_diff_missing(args, left_rules, right_rules) |
||
| 332 | if args.two_plus: |
||
| 333 | process_diff_two_plus(args, left_rules, right_rules) |
||
| 334 | if args.prodtypes: |
||
| 335 | process_diff_prodtypes(args, left_rules, right_rules) |
||
| 336 | if args.product_names: |
||
| 337 | process_diff_product_names(args, left_rules, right_rules) |
||
| 338 | |||
| 339 | |||
| 340 | if __name__ == "__main__": |
||
| 341 | main() |
||
| 342 |