print_docs_diff.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. #!/usr/bin/env python3
  2. import argparse
  3. from collections import defaultdict
  4. import difflib
  5. import pickle
  6. from selfdrive.car.docs import get_all_car_info
  7. from selfdrive.car.docs_definitions import Column
  8. FOOTNOTE_TAG = "<sup>{}</sup>"
  9. STAR_ICON = '<a href="##"><img valign="top" src="https://raw.githubusercontent.com/commaai/openpilot/master/docs/assets/icon-star-{}.svg" width="22" /></a>'
  10. COLUMNS = "|" + "|".join([column.value for column in Column]) + "|"
  11. COLUMN_HEADER = "|---|---|---|{}|".format("|".join([":---:"] * (len(Column) - 3)))
  12. ARROW_SYMBOL = "➡️"
  13. def load_base_car_info(path):
  14. with open(path, "rb") as f:
  15. return pickle.load(f)
  16. def match_cars(base_cars, new_cars):
  17. changes = []
  18. additions = []
  19. for new in new_cars:
  20. # Addition if no close matches or close match already used
  21. # Change if close match and not already used
  22. matches = difflib.get_close_matches(new.name, [b.name for b in base_cars], cutoff=0.)
  23. if not len(matches) or matches[0] in [c[1].name for c in changes]:
  24. additions.append(new)
  25. else:
  26. changes.append((new, next(car for car in base_cars if car.name == matches[0])))
  27. # Removal if base car not in changes
  28. removals = [b for b in base_cars if b.name not in [c[1].name for c in changes]]
  29. return changes, additions, removals
  30. def build_column_diff(base_car, new_car):
  31. row_builder = []
  32. for column in Column:
  33. base_column = base_car.get_column(column, STAR_ICON, FOOTNOTE_TAG)
  34. new_column = new_car.get_column(column, STAR_ICON, FOOTNOTE_TAG)
  35. if base_column != new_column:
  36. row_builder.append(f"{base_column} {ARROW_SYMBOL} {new_column}")
  37. else:
  38. row_builder.append(new_column)
  39. return format_row(row_builder)
  40. def format_row(builder):
  41. return "|" + "|".join(builder) + "|"
  42. def print_car_info_diff(path):
  43. base_car_info = defaultdict(list)
  44. new_car_info = defaultdict(list)
  45. for car in load_base_car_info(path):
  46. base_car_info[car.car_fingerprint].append(car)
  47. for car in get_all_car_info():
  48. new_car_info[car.car_fingerprint].append(car)
  49. # Add new platforms to base cars so we can detect additions and removals in one pass
  50. base_car_info.update({car: [] for car in new_car_info if car not in base_car_info})
  51. changes = defaultdict(list)
  52. for base_car_model, base_cars in base_car_info.items():
  53. # Match car info changes, and get additions and removals
  54. new_cars = new_car_info[base_car_model]
  55. car_changes, car_additions, car_removals = match_cars(base_cars, new_cars)
  56. # Removals
  57. for car_info in car_removals:
  58. changes["removals"].append(format_row([car_info.get_column(column, STAR_ICON, FOOTNOTE_TAG) for column in Column]))
  59. # Additions
  60. for car_info in car_additions:
  61. changes["additions"].append(format_row([car_info.get_column(column, STAR_ICON, FOOTNOTE_TAG) for column in Column]))
  62. for new_car, base_car in car_changes:
  63. # Column changes
  64. row_diff = build_column_diff(base_car, new_car)
  65. if ARROW_SYMBOL in row_diff:
  66. changes["column"].append(row_diff)
  67. # Detail sentence changes
  68. if base_car.detail_sentence != new_car.detail_sentence:
  69. changes["detail"].append(f"- Sentence for {base_car.name} changed!\n" +
  70. " ```diff\n" +
  71. f" - {base_car.detail_sentence}\n" +
  72. f" + {new_car.detail_sentence}\n" +
  73. " ```")
  74. # Print diff
  75. if any(len(c) for c in changes.values()):
  76. markdown_builder = ["### ⚠️ This PR makes changes to [CARS.md](../blob/master/docs/CARS.md) ⚠️"]
  77. for title, category in (("## 🔀 Column Changes", "column"), ("## ❌ Removed", "removals"), ("## ➕ Added", "additions"), ("## 📖 Detail Sentence Changes", "detail")):
  78. if len(changes[category]):
  79. markdown_builder.append(title)
  80. if category not in ("detail",):
  81. markdown_builder.append(COLUMNS)
  82. markdown_builder.append(COLUMN_HEADER)
  83. markdown_builder.extend(changes[category])
  84. print("\n".join(markdown_builder))
  85. if __name__ == "__main__":
  86. parser = argparse.ArgumentParser()
  87. parser.add_argument("--path", required=True)
  88. args = parser.parse_args()
  89. print_car_info_diff(args.path)