pika-patch-tool.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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. try:
  47. diff_output = result.stdout.decode('utf-8')
  48. except Exception as e:
  49. print(f"Failed to decode diff output: {e}")
  50. print("Skipping file:", target_file)
  51. exit(-1)
  52. print(diff_output)
  53. # 使用UTF-8编码打开文件进行写入
  54. with open("/tmp/base/changes.patch", "a", encoding='utf-8') as patch_file:
  55. patch_file.write(diff_output)
  56. else:
  57. print(f"No base file, skipped: {target_file}")
  58. # if there is no patch, exit
  59. if not os.path.exists("/tmp/base/changes.patch"):
  60. # green print
  61. print("\033[92mNothing need to be patched\033[0m")
  62. exit()
  63. # read the patch
  64. with open("/tmp/base/changes.patch", encoding='utf-8') as patch_file:
  65. patch_data = patch_file.read()
  66. # split the patch into a list of patches
  67. patches = []
  68. patch_item = ''
  69. for line in patch_data.split('\n'):
  70. if line.startswith('diff --git'):
  71. if patch_item: # If patch_item is not empty, append it to patches list
  72. patches.append(patch_item)
  73. patch_item = '' # Reset patch_item for the next patch
  74. patch_item += line + '\n'
  75. # Append the last patch_item after the loop ends
  76. if patch_item:
  77. patches.append(patch_item)
  78. main_repo_path = "/tmp/pikapython"
  79. apply_dirs = ["src", "port/linux/package/pikascript", "package"]
  80. search_dirs = [os.path.join(main_repo_path, dir) for dir in apply_dirs]
  81. success_count = 0
  82. success_list = []
  83. fail_count = 0
  84. fail_list = []
  85. for patch in patches:
  86. lines = patch.split('\n')
  87. if len(lines) < 1:
  88. print("No valid patch data, skipped")
  89. continue
  90. header = lines[0]
  91. if not (header.startswith('diff --git a/') or header.startswith('diff --git "a')):
  92. print("No valid patch header, skipped")
  93. continue
  94. paths = header[13:].split(' b/')
  95. if len(paths) != 2:
  96. paths = header[14:].split(' "b/')
  97. if len(paths) != 2:
  98. print("No valid file path in header, skipped")
  99. continue
  100. from_file = paths[0].strip('"')
  101. to_file = paths[1].strip('"')
  102. print(f"Searching for file: {from_file}")
  103. # serch file
  104. is_found = False
  105. for dir in search_dirs:
  106. file_name = os.path.basename(from_file)
  107. # find file
  108. # if is_found:
  109. # break
  110. for root, apply_dirs, files in os.walk(dir):
  111. if file_name in files:
  112. is_found = True
  113. apply_file = os.path.join(root, file_name)
  114. apply_file = os.path.relpath(apply_file, main_repo_path)
  115. # replace \ with /
  116. apply_file = apply_file.replace('\\', '/')
  117. print(f"Found file: {apply_file}")
  118. # replace from_file and to_file with apply_file
  119. patch = patch.replace(from_file, apply_file)
  120. patch = patch.replace(to_file, apply_file)
  121. print(f"Applying patch: {patch}")
  122. # Strip the trailing whitespace for each line
  123. lines = [line for line in patch.split('\n')]
  124. with open("/tmp/base/temp.patch", 'w', encoding='utf-8') as f:
  125. for line in lines:
  126. f.write(line + '\n')
  127. apply_patch_command = ["git", "apply", "/tmp/base/temp.patch"]
  128. result = subprocess.run(
  129. apply_patch_command, stdout=subprocess.PIPE, cwd=main_repo_path)
  130. # check the result
  131. if result.returncode != 0:
  132. fail_count += 1
  133. fail_list.append(apply_file)
  134. print("\033[91mFailed to apply patch:\033[0m", apply_file)
  135. else:
  136. success_count += 1
  137. success_list.append(apply_file)
  138. print(
  139. "\033[92mSuccessfully applied patch\033[0m", apply_file)
  140. break
  141. print("\n\n===========================================\n\n")
  142. print(f"\033[92mTotal patches applied successfully: {success_count}\033[0m")
  143. print("\033[92mSuccessfully applied patches:\033[0m")
  144. for file in success_list:
  145. print(file)
  146. if fail_count > 0:
  147. print(f"\033[91mTotal patches failed to apply: {fail_count}\033[0m")
  148. print("\033[91mFailed to apply patches:\033[0m")
  149. for file in fail_list:
  150. print(file)
  151. # setup remote url
  152. repo_url = input("Please enter your remote repository URL (default: '{}'): ".format(
  153. default_repo_url)) or default_repo_url
  154. subprocess.run(["git", "remote", "set-url", "origin",
  155. repo_url], cwd=main_repo_path)
  156. # setup commit message
  157. commit_msg = input(
  158. "Please enter your commit message (default: 'Apply patches'): ") or "Apply patches"
  159. subprocess.run(["git", "commit", "-a", "-m", commit_msg], cwd=main_repo_path)
  160. # confirm push
  161. confirm = input("Are you sure you want to push to the repository ([Y]/N)? ")
  162. if confirm.lower() != 'n':
  163. # git push
  164. subprocess.run(["git", "push"], cwd=main_repo_path)
  165. else:
  166. print("Push cancelled.")