update.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #!/usr/bin/env python3
  2. """Script for updating data. """
  3. import argparse
  4. import json
  5. import os
  6. import re
  7. import subprocess
  8. from datetime import datetime, timedelta, tzinfo
  9. from tempfile import mkstemp
  10. from typing import Iterator
  11. from zipfile import ZipFile
  12. from tqdm import tqdm
  13. from fetch import CustomJSONEncoder, fetch_holiday
  14. from generate_ics import generate_ics
  15. from filetools import workspace_path
  16. class ChinaTimezone(tzinfo):
  17. """Timezone of china."""
  18. def tzname(self, dt):
  19. return "UTC+8"
  20. def utcoffset(self, dt):
  21. return timedelta(hours=8)
  22. def dst(self, dt):
  23. return timedelta()
  24. def update_data(year: int) -> Iterator[str]:
  25. """Update and store data for a year."""
  26. json_filename = workspace_path(f"{year}.json")
  27. ics_filename = workspace_path(f"{year}.ics")
  28. with open(json_filename, "w", encoding="utf-8", newline="\n") as f:
  29. data = fetch_holiday(year)
  30. json.dump(
  31. dict(
  32. (
  33. (
  34. "$schema",
  35. "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/schema.json",
  36. ),
  37. (
  38. "$id",
  39. f"https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/{year}.json",
  40. ),
  41. *data.items(),
  42. )
  43. ),
  44. f,
  45. indent=4,
  46. ensure_ascii=False,
  47. cls=CustomJSONEncoder,
  48. )
  49. yield json_filename
  50. generate_ics(data["days"], ics_filename)
  51. yield ics_filename
  52. def update_main_ics(fr_year, to_year):
  53. all_days = []
  54. for year in range(fr_year, to_year + 1):
  55. filename = workspace_path(f"{year}.json")
  56. if not os.path.isfile(filename):
  57. continue
  58. with open(filename, "r", encoding="utf8") as inf:
  59. data = json.loads(inf.read())
  60. all_days.extend(data.get("days"))
  61. filename = workspace_path("holiday-cn.ics")
  62. generate_ics(
  63. all_days,
  64. filename,
  65. )
  66. return filename
  67. def main():
  68. parser = argparse.ArgumentParser()
  69. parser.add_argument(
  70. "--all",
  71. action="store_true",
  72. help="Update all years since 2007, default is this year and next year",
  73. )
  74. parser.add_argument(
  75. "--release",
  76. action="store_true",
  77. help="create new release if repository data is not up to date",
  78. )
  79. args = parser.parse_args()
  80. now = datetime.now(ChinaTimezone())
  81. is_release = args.release
  82. filenames = []
  83. progress = tqdm(range(2007 if args.all else now.year, now.year + 2))
  84. for i in progress:
  85. progress.set_description(f"Updating {i} data")
  86. filenames += list(update_data(i))
  87. progress.set_description("Updating holiday-cn.ics")
  88. filenames.append(update_main_ics(now.year - 4, now.year + 1))
  89. print("")
  90. subprocess.run(["git", "add", *filenames], check=True)
  91. diff = subprocess.run(
  92. ["git", "diff", "--stat", "--cached", "*.json", "*.ics"],
  93. check=True,
  94. stdout=subprocess.PIPE,
  95. encoding="utf-8",
  96. ).stdout
  97. if not diff:
  98. print("Already up to date.")
  99. return
  100. if not is_release:
  101. print("Updated repository data, skip release since not specified `--release`")
  102. return
  103. subprocess.run(
  104. [
  105. "git",
  106. "commit",
  107. "-m",
  108. "chore(release): update holiday data",
  109. "-m",
  110. "[skip ci]",
  111. ],
  112. check=True,
  113. )
  114. subprocess.run(["git", "push"], check=True)
  115. tag = now.strftime("%Y.%m.%d")
  116. temp_note_fd, temp_note_name = mkstemp()
  117. with open(temp_note_fd, "w", encoding="utf-8") as f:
  118. f.write(tag + "\n\n```diff\n" + diff + "\n```\n")
  119. os.makedirs(workspace_path("dist"), exist_ok=True)
  120. zip_path = workspace_path("dist", f"holiday-cn-{tag}.zip")
  121. pack_data(zip_path)
  122. subprocess.run(
  123. [
  124. "gh",
  125. "release",
  126. "create",
  127. "-F",
  128. temp_note_name,
  129. tag,
  130. f"{zip_path}#JSON数据",
  131. ],
  132. check=True,
  133. )
  134. os.unlink(temp_note_name)
  135. def pack_data(file):
  136. """Pack data json in zip file."""
  137. zip_file = ZipFile(file, "w")
  138. for i in os.listdir(workspace_path()):
  139. if not re.match(r"\d+\.json", i):
  140. continue
  141. zip_file.write(workspace_path(i), i)
  142. if __name__ == "__main__":
  143. main()