pika-patch-tool.py 6.2 KB

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