Flash.hx 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. package runci.targets;
  2. import sys.FileSystem;
  3. import sys.io.File;
  4. import sys.io.Process;
  5. import haxe.Json;
  6. import haxe.Http;
  7. import haxe.io.Path;
  8. import runci.System.*;
  9. import runci.System.CommandFailure;
  10. import runci.Config.*;
  11. using StringTools;
  12. class Flash {
  13. static final miscFlashDir = getMiscSubDir('flash');
  14. static var playerLocation:String;
  15. static final DEFAULT_APACHE_MIRROR = "https://downloads.apache.org/";
  16. static function getPreferredApacheMirror() {
  17. return try {
  18. Json.parse(Http.requestUrl("https://www.apache.org/dyn/closer.lua?as_json=1")).preferred;
  19. } catch (e) {
  20. failMsg('Unable to determine preferred Apache mirror. Defaulting to $DEFAULT_APACHE_MIRROR');
  21. DEFAULT_APACHE_MIRROR;
  22. };
  23. }
  24. static function downloadAndExtractFlexSdk(version:String, sdkPath:String):Void {
  25. final apacheMirror = getPreferredApacheMirror();
  26. final archiveExtension = if (systemName == "Windows") "zip" else "tar.gz";
  27. final archiveName = 'apache-flex-sdk-${version}-bin.$archiveExtension';
  28. runNetworkCommand("wget", ["-nv", '${apacheMirror}/flex/${version}/binaries/$archiveName', "-O", getDownloadPath() + '/$archiveName']);
  29. if (systemName == "Windows") {
  30. runCommand("7z", ["x", getDownloadPath() + '/$archiveName', "-o" + sdkPath, "-y"]);
  31. } else {
  32. runCommand("tar", ["-xf", getDownloadPath() + '/$archiveName', "-C", getInstallPath()]);
  33. }
  34. }
  35. static function setupFlexSdk():Void {
  36. if (commandSucceed("mxmlc", ["--version"])) {
  37. infoMsg('mxmlc has already been installed.');
  38. return;
  39. }
  40. // download flex sdk
  41. final flexVersion = "4.16.1";
  42. final flexSdkPath = Path.normalize(getInstallPath() + '/apache-flex-sdk-${flexVersion}-bin');
  43. if (FileSystem.exists(flexSdkPath)) {
  44. infoMsg('Flex SDK found at $flexSdkPath');
  45. } else {
  46. downloadAndExtractFlexSdk(flexVersion, flexSdkPath);
  47. }
  48. addToPATH(flexSdkPath + "/bin");
  49. // download playerglobal.swc
  50. final playerGlobalSwcFolder = flexSdkPath + "/player";
  51. final playerGlobalSwcSubFolder = playerGlobalSwcFolder + "/27.0";
  52. FileSystem.createDirectory(playerGlobalSwcSubFolder);
  53. final playerGlobalSwcPath = '$playerGlobalSwcSubFolder/playerglobal.swc';
  54. if (FileSystem.exists(playerGlobalSwcPath)) {
  55. infoMsg('playerglobal.swc found at $playerGlobalSwcPath');
  56. } else {
  57. final flashVersion = getLatestFPVersion();
  58. runNetworkCommand("wget", [
  59. "-nv",
  60. 'https://fpdownload.macromedia.com/get/flashplayer/updaters/${flashVersion[0]}/playerglobal${flashVersion[0]}_${flashVersion[1]}.swc',
  61. "-O",
  62. playerGlobalSwcPath
  63. ]);
  64. }
  65. // set playerglobal.swc
  66. File.saveContent(flexSdkPath + "/env.properties", 'env.PLAYERGLOBAL_HOME=$playerGlobalSwcFolder');
  67. // ensure flex sdk is working
  68. runCommand("mxmlc", ["--version"]);
  69. }
  70. static function getLatestFPVersion():Array<Int> {
  71. final appcast = Xml.parse(haxe.Http.requestUrl("http://fpdownload.macromedia.com/get/flashplayer/update/current/xml/version_en_mac_pep.xml"));
  72. final versionStr = new haxe.xml.Access(appcast).node.XML.node.update.att.version;
  73. return versionStr.split(",").map(Std.parseInt);
  74. }
  75. static function downloadPlayer(version:Int, fileName:String, outputPath:String) {
  76. runNetworkCommand("wget", [
  77. "-nv",
  78. 'https://fpdownload.macromedia.com/pub/flashplayer/updaters/$version/$fileName',
  79. "-O",
  80. '$outputPath/$fileName'
  81. ]);
  82. }
  83. static function setupFlashPlayerMac():Void {
  84. playerLocation = getInstallPath() + "/Flash Player.app";
  85. if (FileSystem.exists(playerLocation))
  86. infoMsg('Flash player found at $playerLocation');
  87. else {
  88. final majorVersion = getLatestFPVersion()[0];
  89. final packageName = 'flashplayer_${majorVersion}_sa_debug.dmg';
  90. downloadPlayer(majorVersion, packageName, getDownloadPath());
  91. runCommand("hdiutil", ["attach", getDownloadPath() + '/$packageName']);
  92. runCommand("cp", ["-R", "/Volumes/Flash Player/Flash Player.app", getInstallPath()]);
  93. runCommand("hdiutil", ["detach", "/Volumes/Flash Player"]);
  94. // Disable the "application downloaded from Internet" warning
  95. runCommand("xattr", ["-d", "-r", "com.apple.quarantine", playerLocation]);
  96. }
  97. runCommand("open", ["-a", playerLocation, "-v"]);
  98. }
  99. static function setupFlashPlayerLinux():Void {
  100. final playerName = "flashplayerdebugger";
  101. playerLocation = Path.join([getInstallPath(), playerName]);
  102. if (Sys.command("type", [playerName]) == 0) {
  103. playerLocation = playerName;
  104. infoMsg('Using $playerName from PATH');
  105. } else if(FileSystem.exists(playerLocation)) {
  106. infoMsg('Flash player found at $playerLocation');
  107. } else {
  108. Linux.requireAptPackages(["libglib2.0-0", "libfreetype6"]);
  109. final tarFileName = 'flash_player_sa_linux_debug.x86_64.tar.gz';
  110. downloadPlayer(getLatestFPVersion()[0], tarFileName, getDownloadPath());
  111. runCommand("tar", ["-xf", getDownloadPath() + '/$tarFileName', "-C", getInstallPath()]);
  112. }
  113. // ensure the debugger works
  114. switch (ci) {
  115. case GithubActions:
  116. runCommand("xvfb-run", ["-a", playerLocation, "-v"]);
  117. case _:
  118. runCommand(playerLocation, ["-v"]);
  119. }
  120. }
  121. static function setupFlashPlayerWindows():Void {
  122. final majorVersion = getLatestFPVersion()[0];
  123. final exeName = 'flashplayer_${majorVersion}_sa_debug.exe';
  124. playerLocation = Path.join([getInstallPath(), exeName]);
  125. if (FileSystem.exists(playerLocation))
  126. infoMsg('Flash player found at $playerLocation');
  127. else
  128. downloadPlayer(majorVersion, exeName, getInstallPath());
  129. }
  130. static function setupFlashPlayer():Void {
  131. switch (systemName) {
  132. case "Linux":
  133. setupFlashPlayerLinux();
  134. case "Mac":
  135. setupFlashPlayerMac();
  136. case "Windows":
  137. setupFlashPlayerWindows();
  138. case _:
  139. throw "unsupported system";
  140. }
  141. }
  142. static function readUntil(stdout:haxe.io.Input, expected:String, ?unexpectedStrings:Map<String, ()->Void>) {
  143. final possibleStrings = unexpectedStrings?.copy() ?? [];
  144. possibleStrings[expected] = function() {};
  145. var output = "";
  146. while (true) {
  147. final char = try {
  148. String.fromCharCode(stdout.readByte());
  149. } catch (e:haxe.io.Eof) {
  150. failMsg('Expected to find "$expected" in stdout');
  151. throw new CommandFailure();
  152. };
  153. Sys.print(char);
  154. output += char;
  155. for (string => onMatch in possibleStrings) {
  156. if (output.endsWith(string)) {
  157. onMatch();
  158. return;
  159. }
  160. }
  161. }
  162. }
  163. /**
  164. Run a Flash swf file.
  165. Throws `CommandFailure` if unsuccessful.
  166. */
  167. static function runFlash(swf:String):Void {
  168. swf = FileSystem.fullPath(swf);
  169. infoMsg('Running .swf file: $swf');
  170. final debuggerProcess = new Process("fdb");
  171. final FDB_PROMPT = "(fdb) ";
  172. // waits for the fdb prompt and runs a command
  173. function runDebuggerCommand(command:String) {
  174. readUntil(debuggerProcess.stdout, FDB_PROMPT);
  175. Sys.println(command);
  176. debuggerProcess.stdin.writeString('$command\n');
  177. }
  178. runDebuggerCommand("run");
  179. function onUnexpectedPrompt() {
  180. Sys.println("quit");
  181. debuggerProcess.stdin.writeString("quit\n");
  182. throw new CommandFailure();
  183. }
  184. readUntil(debuggerProcess.stdout, "Waiting for Player to connect", [FDB_PROMPT => onUnexpectedPrompt]);
  185. final playerProcess = switch (systemName) {
  186. case "Linux" if (ci == GithubActions):
  187. new Process("xvfb-run", ["-a", playerLocation, swf]);
  188. case "Mac":
  189. new Process("open", ["-a", playerLocation, swf]);
  190. default:
  191. new Process(playerLocation, [swf]);
  192. };
  193. readUntil(debuggerProcess.stdout, "Player connected; session starting.", [FDB_PROMPT => onUnexpectedPrompt]);
  194. runDebuggerCommand("continue");
  195. var success = true;
  196. readUntil(debuggerProcess.stdout, "(success: true)", [
  197. FDB_PROMPT => onUnexpectedPrompt,
  198. "(success: false)" => () -> { success = false; }
  199. ]);
  200. runDebuggerCommand("quit");
  201. debuggerProcess.kill();
  202. debuggerProcess.close();
  203. playerProcess.kill();
  204. playerProcess.close();
  205. if (!success)
  206. throw new CommandFailure();
  207. }
  208. static public function run(args:Array<String>) {
  209. setupFlashPlayer();
  210. setupFlexSdk();
  211. for (flashVersion in ["11", "32"]) {
  212. runCommand("haxe", ["compile-flash.hxml", "-D", "fdb", "-D", "dump", "-D", "dump_ignore_var_ids", "--swf-version", flashVersion].concat(args));
  213. runFlash("bin/unit.swf");
  214. }
  215. Display.maybeRunDisplayTests(Flash);
  216. changeDirectory(miscFlashDir);
  217. runCommand("haxe", ["run.hxml"]);
  218. }
  219. }