pika-patch-tool.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import os
  2. import shutil
  3. import subprocess
  4. default_repo_url = "https://gitee.com/lyon1998/pikapython"
  5. # clone pikapython repo
  6. repo_path = "/tmp/pikapython"
  7. if not os.path.exists(repo_path):
  8. subprocess.run(["git", "clone", default_repo_url, repo_path])
  9. else:
  10. # if the repo exists, clean all uncommitted changes
  11. subprocess.run(["git", "reset", "--hard"], cwd=repo_path)
  12. subprocess.run(["git", "clean", "-fd"], cwd=repo_path)
  13. # switch to master branch
  14. subprocess.run(["git", "checkout", "master"], cwd=repo_path)
  15. # fetch updates from remote repository
  16. subprocess.run(["git", "fetch"], cwd=repo_path)
  17. # force update local master branch to match remote master branch
  18. subprocess.run(["git", "reset", "--hard", "origin/master"], cwd=repo_path)
  19. # create the base of the patch
  20. base_path = "/tmp/base"
  21. if os.path.exists(base_path):
  22. shutil.rmtree(base_path)
  23. os.mkdir(base_path)
  24. # install the base package
  25. for file_name in ["pikaPackage.exe", "requestment.txt"]:
  26. shutil.copy(file_name, base_path)
  27. with open(os.path.join(base_path, "main.py"), "w") as f:
  28. f.write("")
  29. subprocess.run(["./pikaPackage.exe"], cwd=base_path)
  30. os.remove(os.path.join(base_path, "main.py"))
  31. # generate the patch
  32. for root, apply_dirs, files in os.walk('.'):
  33. if 'pikascript-api' in root: # skip the pikascript-api folder
  34. continue
  35. for file in files:
  36. src_file = os.path.join(root, file)
  37. rel_path = os.path.relpath(root, '.')
  38. target_file = os.path.join(base_path, rel_path, file)
  39. print(f"Processing file: {src_file}")
  40. if os.path.exists(target_file):
  41. diff_command = ["git", "diff",
  42. "--no-index", target_file, src_file]
  43. result = subprocess.run(diff_command, stdout=subprocess.PIPE)
  44. if result.stdout:
  45. # 确保使用UTF-8编码解码stdout
  46. diff_output = result.stdout.decode('utf-8')
  47. print(diff_output)
  48. # 使用UTF-8编码打开文件进行写入
  49. with open("/tmp/base/changes.patch", "a", encoding='utf-8') as patch_file:
  50. patch_file.write(diff_output)
  51. else:
  52. print(f"No base file, skipped: {target_file}")
  53. # if there is no patch, exit
  54. if not os.path.exists("/tmp/base/changes.patch"):
  55. # green print
  56. print("\033[92mNothing need to be patched\033[0m")
  57. exit()
  58. # read the patch
  59. with open("/tmp/base/changes.patch", encoding='utf-8') as patch_file:
  60. patch_data = patch_file.read()
  61. # split the patch into a list of patches
  62. patches = []
  63. patch_item = ''
  64. for line in patch_data.split('\n'):
  65. if line.startswith('diff --git'):
  66. if patch_item: # If patch_item is not empty, append it to patches list
  67. patches.append(patch_item)
  68. patch_item = '' # Reset patch_item for the next patch
  69. patch_item += line + '\n'
  70. # Append the last patch_item after the loop ends
  71. if patch_item:
  72. patches.append(patch_item)
  73. main_repo_path = "/tmp/pikapython"
  74. apply_dirs = ["src", "port/linux/package/pikascript", "package"]
  75. search_dirs = [os.path.join(main_repo_path, dir) for dir in apply_dirs]
  76. success_count = 0
  77. success_list = []
  78. fail_count = 0
  79. fail_list = []
  80. for patch in patches:
  81. lines = patch.split('\n')
  82. if len(lines) < 1:
  83. print("No valid patch data, skipped")
  84. continue
  85. header = lines[0]
  86. if not (header.startswith('diff --git a/') or header.startswith('diff --git "a')):
  87. print("No valid patch header, skipped")
  88. continue
  89. paths = header[13:].split(' b/')
  90. if len(paths) != 2:
  91. paths = header[14:].split(' "b/')
  92. if len(paths) != 2:
  93. print("No valid file path in header, skipped")
  94. continue
  95. from_file = paths[0].strip('"')
  96. to_file = paths[1].strip('"')
  97. print(f"Searching for file: {from_file}")
  98. # serch file
  99. is_found = False
  100. for dir in search_dirs:
  101. file_name = os.path.basename(from_file)
  102. # find file
  103. # if is_found:
  104. # break
  105. for root, apply_dirs, files in os.walk(dir):
  106. if file_name in files:
  107. is_found = True
  108. apply_file = os.path.join(root, file_name)
  109. apply_file = os.path.relpath(apply_file, main_repo_path)
  110. # replace \ with /
  111. apply_file = apply_file.replace('\\', '/')
  112. print(f"Found file: {apply_file}")
  113. # replace from_file and to_file with apply_file
  114. patch = patch.replace(from_file, apply_file)
  115. patch = patch.replace(to_file, apply_file)
  116. print(f"Applying patch: {patch}")
  117. # Strip the trailing whitespace for each line
  118. lines = [line for line in patch.split('\n')]
  119. with open("/tmp/base/temp.patch", 'w', encoding='utf-8') as f:
  120. for line in lines:
  121. f.write(line + '\n')
  122. apply_patch_command = ["git", "apply", "/tmp/base/temp.patch"]
  123. result = subprocess.run(
  124. apply_patch_command, stdout=subprocess.PIPE, cwd=main_repo_path)
  125. # check the result
  126. if result.returncode != 0:
  127. fail_count += 1
  128. fail_list.append(apply_file)
  129. print("\033[91mFailed to apply patch:\033[0m", apply_file)
  130. else:
  131. success_count += 1
  132. success_list.append(apply_file)
  133. print(
  134. "\033[92mSuccessfully applied patch\033[0m", apply_file)
  135. break
  136. print("\n\n===========================================\n\n")
  137. print(f"\033[92mTotal patches applied successfully: {success_count}\033[0m")
  138. print("\033[92mSuccessfully applied patches:\033[0m")
  139. for file in success_list:
  140. print(file)
  141. if fail_count > 0:
  142. print(f"\033[91mTotal patches failed to apply: {fail_count}\033[0m")
  143. print("\033[91mFailed to apply patches:\033[0m")
  144. for file in fail_list:
  145. print(file)
  146. # setup remote url
  147. repo_url = input("Please enter your remote repository URL (default: '{}'): ".format(
  148. default_repo_url)) or default_repo_url
  149. subprocess.run(["git", "remote", "set-url", "origin",
  150. repo_url], cwd=main_repo_path)
  151. # setup commit message
  152. commit_msg = input(
  153. "Please enter your commit message (default: 'Apply patches'): ") or "Apply patches"
  154. subprocess.run(["git", "commit", "-a", "-m", commit_msg], cwd=main_repo_path)
  155. # confirm push
  156. confirm = input("Are you sure you want to push to the repository ([Y]/N)? ")
  157. if confirm.lower() != 'n':
  158. # git push
  159. subprocess.run(["git", "push"], cwd=main_repo_path)
  160. else:
  161. print("Push cancelled.")