You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

279 lines
8.0KB

  1. import sys
  2. import os
  3. import glob
  4. import json
  5. import time
  6. import re
  7. import tempfile
  8. import random
  9. import functools
  10. import common
  11. import update_modulargrid
  12. import update_cache
  13. TOOLCHAIN_DIR = "../toolchain-v2"
  14. PACKAGES_DIR = "../packages"
  15. MANIFESTS_DIR = "manifests"
  16. RACK_SYSTEM_DIR = "../Rack2"
  17. RACK_USER_DIR = "$HOME/.local/share/Rack2"
  18. SCREENSHOTS_DIR = os.path.join(RACK_USER_DIR, "screenshots")
  19. PLUGIN_DIR = os.path.join(RACK_USER_DIR, "plugins-lin-x64")
  20. FILES_DIR = "../files/packages"
  21. def version_part_less(a, b):
  22. try:
  23. ai = int(a)
  24. except ValueError:
  25. ai = None
  26. try:
  27. bi = int(b)
  28. except ValueError:
  29. bi = None
  30. if ai is not None and bi is not None:
  31. return ai < bi
  32. elif ai is not None:
  33. return False
  34. elif bi is not None:
  35. return True
  36. else:
  37. return a < b
  38. def version_less(a, b):
  39. a_parts = a.split(".")
  40. b_parts = b.split(".")
  41. for a_part, b_part in zip(a_parts, b_parts):
  42. if a_part == b_part:
  43. continue
  44. return version_part_less(a_part, b_part)
  45. return len(a_parts) < len(b_parts)
  46. def package_exists(slug, version, os_, cpu):
  47. if os.path.isfile(os.path.join(PACKAGES_DIR, f"{slug}-{version}-{os_}-{cpu}.vcvplugin")):
  48. return True
  49. if cpu == 'x64':
  50. if os.path.isfile(os.path.join(PACKAGES_DIR, f"{slug}-{version}-{os_}.vcvplugin")):
  51. return True
  52. return False
  53. # Get missing Mac ARM64 slugs
  54. def print_missing_mac_arm64():
  55. emails = set()
  56. for manifest_path in glob.glob("manifests/*.json"):
  57. with open(manifest_path, "r") as f:
  58. manifest = json.load(f)
  59. slug = manifest['slug']
  60. version = manifest['version']
  61. author = manifest['author']
  62. license = manifest.get('license', "")
  63. email = manifest.get('authorEmail', "")
  64. if not package_exists(slug, version, 'mac', 'x64'):
  65. continue
  66. if package_exists(slug, version, 'mac', 'arm64'):
  67. continue
  68. print(f"{slug} {version}\t\t{email}\t\t{license}")
  69. # Update git before continuing
  70. common.system_retry("git pull")
  71. common.system("git submodule sync --recursive --quiet")
  72. common.system("git submodule update --init --recursive")
  73. plugin_paths = sys.argv[1:]
  74. # Default to all repos, so all out-of-date repos are built
  75. if not plugin_paths:
  76. plugin_paths = glob.glob("repos/*")
  77. plugin_paths.sort()
  78. # Randomize repo order
  79. # plugin_paths = random.sample(plugin_paths, len(plugin_paths))
  80. manifest_versions = {}
  81. for plugin_path in plugin_paths:
  82. plugin_path = os.path.abspath(plugin_path)
  83. (plugin_basename, plugin_ext) = os.path.splitext(os.path.basename(plugin_path))
  84. # Get manifest
  85. # Source dir
  86. if os.path.isdir(plugin_path):
  87. manifest_filename = os.path.join(plugin_path, "plugin.json")
  88. try:
  89. # Read manifest
  90. with open(manifest_filename, "r") as f:
  91. manifest = json.load(f)
  92. except IOError:
  93. # Skip plugins without plugin.json
  94. continue
  95. slug = manifest['slug']
  96. version = manifest['version']
  97. # Plugin package
  98. elif plugin_ext == ".vcvplugin":
  99. m = re.match(r'^(.*)-(\d\..*?)-(.*?)-(.*?)$', plugin_basename)
  100. if not m:
  101. raise Exception(f"Filename {plugin_path} invalid format")
  102. slug = m[1]
  103. version = m[2]
  104. os_ = m[3]
  105. cpu = m[4]
  106. # Extract ZIP to temp dir
  107. try:
  108. tempdir = tempfile.mkdtemp()
  109. common.system(f'zstd -d < "{plugin_path}" | tar -x -C "{tempdir}"')
  110. # Read manifest
  111. manifest_filename = os.path.join(tempdir, slug, "plugin.json")
  112. with open(manifest_filename) as f:
  113. manifest = json.load(f)
  114. if manifest['slug'] != slug:
  115. raise Exception(f"Manifest slug {manifest['slug']} does not match filename slug {slug}")
  116. if manifest['version'] != version:
  117. raise Exception(f"Manifest version {manifest['version']} does not match filename version {version}")
  118. finally:
  119. common.system(f'rm -rf "{tempdir}"')
  120. else:
  121. raise Exception(f"Plugin {plugin_path} is not a valid format")
  122. # Slug blacklist
  123. # if slug == 'questionablemodules':
  124. # continue
  125. # Get library manifest
  126. library_manifest_filename = os.path.join(MANIFESTS_DIR, f"{slug}.json")
  127. library_manifest = None
  128. try:
  129. with open(library_manifest_filename, "r") as f:
  130. library_manifest = json.load(f)
  131. except IOError:
  132. # Warn if manifest is new
  133. # print(f"Manifest {slug} is new, press enter to approve.")
  134. # if input() != '':
  135. # continue
  136. pass
  137. # Ensure that no modules are removed from library
  138. if library_manifest:
  139. library_modules = set(module['slug'] for module in library_manifest['modules'])
  140. modules = set(module['slug'] for module in manifest['modules'])
  141. removed_modules = library_modules - modules
  142. if removed_modules:
  143. raise Exception(f"Plugin {slug} removes modules {", ".join(removed_modules)}")
  144. # Source dir
  145. if os.path.isdir(plugin_path):
  146. # Ensure that version is higher than library version
  147. if library_manifest:
  148. # if not version_less(library_manifest['version'], version):
  149. if library_manifest['version'] == version:
  150. continue
  151. print()
  152. print(f"Building {slug}")
  153. try:
  154. # Clean repo
  155. common.system(f'cd "{TOOLCHAIN_DIR}" && make plugin-build-clean')
  156. # Build repo for each arch
  157. common.system(f'cd "{TOOLCHAIN_DIR}" && make -j2 plugin-build-mac-arm64 PLUGIN_DIR="{plugin_path}"')
  158. common.system(f'cd "{TOOLCHAIN_DIR}" && make -j2 plugin-build-mac-x64 PLUGIN_DIR="{plugin_path}"')
  159. common.system(f'cd "{TOOLCHAIN_DIR}" && make -j2 plugin-build-win-x64 PLUGIN_DIR="{plugin_path}"')
  160. common.system(f'cd "{TOOLCHAIN_DIR}" && make -j2 plugin-build-lin-x64 PLUGIN_DIR="{plugin_path}"')
  161. # Copy package to packages dir
  162. common.system(f'cp -v "{TOOLCHAIN_DIR}"/plugin-build/* "{PACKAGES_DIR}"/')
  163. # Copy packages to files dir for testing
  164. common.system(f'cp -v "{TOOLCHAIN_DIR}"/plugin-build/* "{FILES_DIR}"/')
  165. # Install Linux package for testing
  166. common.system(f'cp -v "{TOOLCHAIN_DIR}"/plugin-build/*-lin-x64.vcvplugin "{PLUGIN_DIR}"/')
  167. except Exception as e:
  168. print(e)
  169. print(f"{slug} build failed")
  170. input()
  171. continue
  172. finally:
  173. common.system(f'cd "{TOOLCHAIN_DIR}" && make plugin-build-clean')
  174. # Open plugin issue thread
  175. os.system(f"xdg-open 'https://github.com/VCVRack/library/issues?q=is%3Aissue+sort%3Aupdated-desc+in%3Atitle+{slug}' &")
  176. # Plugin package
  177. elif plugin_ext == ".vcvplugin":
  178. # Review manifest for errors
  179. print(json.dumps(manifest, indent=" "))
  180. print("Press enter to approve manifest")
  181. input()
  182. # Copy package
  183. common.system(f'cp "{plugin_path}" "{PACKAGES_DIR}/"')
  184. # Update file timestamp
  185. package_filename = os.path.basename(plugin_path)
  186. common.system(f'touch "{PACKAGES_DIR}/{package_filename}"')
  187. # Copy Mac ARM64 package to files dir for testing
  188. # if os_ == 'mac' and cpu == 'arm64':
  189. # common.system(f'cp -v "{plugin_path}" "{FILES_DIR}"/')
  190. # Install Linux package for testing
  191. if os_ == 'lin':
  192. common.system(f'cp "{plugin_path}" "{PLUGIN_DIR}/"')
  193. # Copy manifest
  194. with open(library_manifest_filename, "w") as f:
  195. json.dump(manifest, f, indent=" ")
  196. # Delete screenshot cache
  197. screenshots_dir = os.path.join(SCREENSHOTS_DIR, slug)
  198. common.system(f'rm -rf "{screenshots_dir}"')
  199. manifest_versions[slug] = version
  200. manifest_versions_str = ", ".join(map(lambda pair: pair[0] + " to " + pair[1], manifest_versions.items()))
  201. if not manifest_versions:
  202. print("Nothing to build")
  203. exit(0)
  204. update_cache.update()
  205. update_modulargrid.update()
  206. # Test plugins
  207. print()
  208. print(f"Press enter to launch Rack and test the following packages: {manifest_versions_str}")
  209. input()
  210. common.system_retry(f"cd {RACK_SYSTEM_DIR} && ./Rack")
  211. common.system(f"cd {RACK_USER_DIR} && grep -P '\\bwarn|debug\\b' log.txt || true")
  212. print(f"Press enter to generate screenshots, upload packages, upload screenshots, and commit/push the library repo.")
  213. input()
  214. common.system_retry(f"cd {RACK_SYSTEM_DIR} && ./Rack -t 4")
  215. # Generate screenshots
  216. common.system_retry("cd ../screenshots && make -j$(nproc)")
  217. # Upload packages
  218. common.system_retry("cd ../packages && make upload")
  219. # Upload screenshots
  220. common.system_retry("cd ../screenshots && make upload")
  221. # Commit git repo
  222. common.system("git add manifests")
  223. common.system("git add manifests-cache.json ModularGrid-VCVLibrary.json")
  224. common.system_retry(f"git commit -m 'Update manifest {manifest_versions_str}'")
  225. common.system_retry("git push")
  226. print()
  227. print(f"Updated {manifest_versions_str}")