RunCi.hx 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201
  1. using StringTools;
  2. import yaml.*;
  3. import sys.*;
  4. import sys.io.*;
  5. import haxe.*;
  6. import haxe.io.*;
  7. private typedef TravisConfig = {
  8. before_install: Array<String>,
  9. script: Array<String>
  10. }
  11. /**
  12. List of "TEST" defined in the "matrix" section of ".travis.yml".
  13. */
  14. @:enum abstract TEST(String) from String {
  15. var Macro = "macro";
  16. var Neko = "neko";
  17. var Js = "js";
  18. var Lua = "lua";
  19. var Php = "php";
  20. var Cpp = "cpp";
  21. var Flash9 = "flash9";
  22. var As3 = "as3";
  23. var Java = "java";
  24. var Cs = "cs";
  25. var Python = "python";
  26. var Hl = "hl";
  27. var ThirdParty = "third-party";
  28. }
  29. enum Ci {
  30. TravisCI;
  31. AppVeyor;
  32. }
  33. enum Failure {
  34. Fail;
  35. }
  36. /**
  37. Will be run by CI services, currently TravisCI and AppVeyor.
  38. TravisCI:
  39. Setting file: ".travis.yml".
  40. Build result: https://travis-ci.org/HaxeFoundation/haxe
  41. AppVeyor:
  42. Setting file: "appveyor.yml".
  43. Build result: https://ci.appveyor.com/project/HaxeFoundation/haxe
  44. */
  45. class RunCi {
  46. static function successMsg(msg:String):Void {
  47. Sys.println('\x1b[32m' + msg + '\x1b[0m');
  48. }
  49. static function failMsg(msg:String):Void {
  50. Sys.println('\x1b[31m' + msg + '\x1b[0m');
  51. }
  52. static function infoMsg(msg:String):Void {
  53. Sys.println('\x1b[36m' + msg + '\x1b[0m');
  54. }
  55. static function fail():Void {
  56. success = false;
  57. throw Fail;
  58. }
  59. /**
  60. Run a command using `Sys.command()`.
  61. If the command exits with non-zero code, exit the whole script with the same code.
  62. If `useRetry` is `true`, the command will be re-run if it exits with non-zero code (3 trials).
  63. It is useful for running network-dependent commands.
  64. */
  65. static function runCommand(cmd:String, ?args:Array<String>, useRetry:Bool = false, allowFailure:Bool = false):Void {
  66. var trials = useRetry ? 3 : 1;
  67. var exitCode:Int = 1;
  68. var cmdStr = cmd + (args == null ? '' : ' $args');
  69. while (trials-->0) {
  70. Sys.println('Command: $cmdStr');
  71. var t = Timer.stamp();
  72. exitCode = Sys.command(cmd, args);
  73. var dt = Math.round(Timer.stamp() - t);
  74. if (exitCode == 0)
  75. successMsg('Command exited with $exitCode in ${dt}s: $cmdStr');
  76. else
  77. failMsg('Command exited with $exitCode in ${dt}s: $cmdStr');
  78. if (exitCode == 0) {
  79. return;
  80. } else if (trials > 0) {
  81. Sys.println('Command will be re-run...');
  82. }
  83. }
  84. if (!allowFailure)
  85. fail();
  86. }
  87. static function isAptPackageInstalled(aptPackage:String):Bool {
  88. return commandSucceed("dpkg-query", ["-W", "-f='${Status}'", aptPackage]);
  89. }
  90. static function requireAptPackages(packages:Array<String>):Void {
  91. var notYetInstalled = [for (p in packages) if (!isAptPackageInstalled(p)) p];
  92. if (notYetInstalled.length > 0)
  93. runCommand("sudo", ["apt-get", "install", "-y"].concat(notYetInstalled), true);
  94. }
  95. static function haxelibInstallGit(account:String, repository:String, ?branch:String, ?srcPath:String, useRetry:Bool = false, ?altName:String):Void {
  96. var name:String = (altName == null) ? repository : altName;
  97. try {
  98. getHaxelibPath(name);
  99. infoMsg('$name has already been installed.');
  100. } catch (e:Dynamic) {
  101. var args:Array<String> = ["git", name, 'https://github.com/$account/$repository'];
  102. if (branch != null) {
  103. args.push(branch);
  104. }
  105. if (srcPath != null) {
  106. args.push(srcPath);
  107. }
  108. runCommand("haxelib", args, useRetry);
  109. }
  110. }
  111. static function haxelibInstall(library:String):Void {
  112. try {
  113. getHaxelibPath(library);
  114. infoMsg('$library has already been installed.');
  115. } catch (e:Dynamic) {
  116. runCommand("haxelib", ["install", library]);
  117. }
  118. }
  119. static function haxelibRun(args:Array<String>, useRetry:Bool = false):Void {
  120. runCommand("haxelib", ["run"].concat(args), useRetry);
  121. }
  122. static function getHaxelibPath(libName:String) {
  123. var proc = new Process("haxelib", ["path", libName]);
  124. var result;
  125. var code = proc.exitCode();
  126. do {
  127. result = proc.stdout.readLine();
  128. if (!result.startsWith("-L")) {
  129. break;
  130. }
  131. } while(true);
  132. proc.close();
  133. if (code != 0) {
  134. throw 'Failed to get haxelib path ($result)';
  135. }
  136. return result;
  137. }
  138. static function changeDirectory(path:String) {
  139. Sys.println('Changing directory to $path');
  140. Sys.setCwd(path);
  141. }
  142. static function setupFlashPlayerDebugger():Void {
  143. var mmcfgPath = switch (systemName) {
  144. case "Linux":
  145. Sys.getEnv("HOME") + "/mm.cfg";
  146. case "Mac":
  147. "/Library/Application Support/Macromedia/mm.cfg";
  148. case _:
  149. throw "unsupported system";
  150. }
  151. switch (systemName) {
  152. case "Linux":
  153. requireAptPackages([
  154. "libcurl3:i386", "libglib2.0-0:i386", "libx11-6:i386", "libxext6:i386",
  155. "libxt6:i386", "libxcursor1:i386", "libnss3:i386", "libgtk2.0-0:i386"
  156. ]);
  157. runCommand("wget", ["-nv", "http://fpdownload.macromedia.com/pub/flashplayer/updaters/11/flashplayer_11_sa_debug.i386.tar.gz"], true);
  158. runCommand("tar", ["-xf", "flashplayer_11_sa_debug.i386.tar.gz", "-C", Sys.getEnv("HOME")]);
  159. File.saveContent(mmcfgPath, "ErrorReportingEnable=1\nTraceOutputFileEnable=1");
  160. runCommand(Sys.getEnv("HOME") + "/flashplayerdebugger", ["-v"]);
  161. case "Mac":
  162. runCommand("brew", ["cask", "install", "flash-player-debugger"]);
  163. var dir = Path.directory(mmcfgPath);
  164. runCommand("sudo", ["mkdir", "-p", dir]);
  165. runCommand("sudo", ["chmod", "a+w", dir]);
  166. File.saveContent(mmcfgPath, "ErrorReportingEnable=1\nTraceOutputFileEnable=1");
  167. }
  168. }
  169. /**
  170. Run a Flash swf file.
  171. Return whether the test is successful or not.
  172. It detemines the test result by reading the flashlog.txt, looking for "SUCCESS: true".
  173. */
  174. static function runFlash(swf:String):Bool {
  175. swf = FileSystem.fullPath(swf);
  176. Sys.println('going to run $swf');
  177. switch (systemName) {
  178. case "Linux":
  179. new Process(Sys.getEnv("HOME") + "/flashplayerdebugger", [swf]);
  180. case "Mac":
  181. Sys.command("open", ["-a", "/Applications/Flash Player Debugger.app", swf]);
  182. }
  183. //wait a little until flashlog.txt is created
  184. var flashlogPath = switch (systemName) {
  185. case "Linux":
  186. Sys.getEnv("HOME") + "/.macromedia/Flash_Player/Logs/flashlog.txt";
  187. case "Mac":
  188. Sys.getEnv("HOME") + "/Library/Preferences/Macromedia/Flash Player/Logs/flashlog.txt";
  189. case _:
  190. throw "unsupported system";
  191. }
  192. for (t in 0...5) {
  193. runCommand("sleep", ["2"]);
  194. if (FileSystem.exists(flashlogPath))
  195. break;
  196. }
  197. if (!FileSystem.exists(flashlogPath)) {
  198. failMsg('$flashlogPath not found.');
  199. return false;
  200. }
  201. //read flashlog.txt continously
  202. var traceProcess = new Process("tail", ["-f", flashlogPath]);
  203. var line = "";
  204. while (true) {
  205. try {
  206. line = traceProcess.stdout.readLine();
  207. Sys.println(line);
  208. if (line.indexOf("SUCCESS: ") >= 0) {
  209. return line.indexOf("SUCCESS: true") >= 0;
  210. }
  211. } catch (e:haxe.io.Eof) {
  212. break;
  213. }
  214. }
  215. return false;
  216. }
  217. static function runCs(exe:String, ?args:Array<String>):Void {
  218. if (args == null) args = [];
  219. exe = FileSystem.fullPath(exe);
  220. switch (systemName) {
  221. case "Linux", "Mac":
  222. runCommand("mono", [exe].concat(args));
  223. case "Windows":
  224. runCommand(exe, args);
  225. switch (ci) {
  226. case AppVeyor:
  227. // https://github.com/HaxeFoundation/haxe/issues/4873
  228. // runCommand("mono", [exe].concat(args));
  229. case _:
  230. //pass
  231. }
  232. }
  233. }
  234. static function runCpp(bin:String, ?args:Array<String>):Void {
  235. if (args == null) args = [];
  236. bin = FileSystem.fullPath(bin);
  237. runCommand(bin, args);
  238. }
  239. static function parseCommand(cmd:String) {
  240. var args = [];
  241. var offset = 0;
  242. var cur = new StringBuf();
  243. var inString = false;
  244. while(true) {
  245. switch(cmd.fastCodeAt(offset++)) {
  246. case '"'.code:
  247. inString = !inString;
  248. case ' '.code if (!inString):
  249. if (cur.length > 0) {
  250. args.push(cur.toString());
  251. cur = new StringBuf();
  252. }
  253. case '\\'.code:
  254. cur.addChar(cmd.fastCodeAt(offset++));
  255. case "$".code:
  256. switch (cmd.fastCodeAt(offset)) {
  257. case '('.code:
  258. ++offset;
  259. var env = new StringBuf();
  260. while(true) {
  261. switch(cmd.fastCodeAt(offset++)) {
  262. case ')'.code:
  263. break;
  264. case c:
  265. env.addChar(c);
  266. }
  267. }
  268. cur.add(Sys.getEnv(env.toString()));
  269. case _:
  270. cur.addChar("$".code);
  271. }
  272. case c:
  273. cur.addChar(c);
  274. }
  275. if (offset == cmd.length) {
  276. break;
  277. }
  278. }
  279. if (cur.length > 0) {
  280. args.push(cur.toString());
  281. }
  282. return args;
  283. }
  284. //static function parseTravisFile(path:String, ignoreBeforeInstall = false) {
  285. //var yaml:TravisConfig = yaml.Yaml.read(path, Parser.options().useObjects());
  286. //if (!ignoreBeforeInstall) {
  287. //for (code in yaml.before_install) {
  288. //var args = parseCommand(code);
  289. //var cmd = args.shift();
  290. //runCommand(cmd, args);
  291. //}
  292. //}
  293. //for (code in yaml.script) {
  294. //var args = parseCommand(code);
  295. //var cmd = args.shift();
  296. //runCommand(cmd, args);
  297. //}
  298. //}
  299. static function commandSucceed(cmd:String, args:Array<String>):Bool {
  300. return try {
  301. var p = new Process(cmd, args);
  302. var succeed = p.exitCode() == 0;
  303. p.close();
  304. succeed;
  305. } catch(e:Dynamic) false;
  306. }
  307. static function commandResult(cmd:String, args:Array<String>):{
  308. stdout:String,
  309. stderr:String,
  310. exitCode:Int
  311. } {
  312. var p = new Process(cmd, args);
  313. var out = {
  314. stdout: p.stdout.readAll().toString(),
  315. stderr: p.stderr.readAll().toString(),
  316. exitCode: p.exitCode()
  317. }
  318. p.close();
  319. return out;
  320. }
  321. static function addToPATH(path:String):Void {
  322. switch (systemName) {
  323. case "Windows":
  324. Sys.putEnv("PATH", Sys.getEnv("PATH") + ";" + path);
  325. case "Mac", "Linux":
  326. Sys.putEnv("PATH", Sys.getEnv("PATH") + ":" + path);
  327. }
  328. }
  329. static function getPhpDependencies() {
  330. switch (systemName) {
  331. case "Linux":
  332. var phpCmd = commandResult("php", ["-v"]);
  333. var phpVerReg = ~/PHP ([0-9]+\.[0-9]+)/i;
  334. var phpVer = if (phpVerReg.match(phpCmd.stdout))
  335. Std.parseFloat(phpVerReg.matched(1));
  336. else
  337. null;
  338. if (phpCmd.exitCode == 0 && phpVer != null && phpVer >= 5.5) {
  339. infoMsg('php has already been installed.');
  340. } else {
  341. requireAptPackages(["php5-cli", "php5-mysql", "php5-sqlite"]);
  342. }
  343. case "Mac":
  344. //pass
  345. case "Windows":
  346. if (commandSucceed("php", ["-v"])) {
  347. infoMsg('php has already been installed.');
  348. } else {
  349. runCommand("cinst", ["php", "-version", "5.6.3", "-y"], true);
  350. addToPATH("C:\\tools\\php");
  351. }
  352. }
  353. runCommand("php", ["-v"]);
  354. }
  355. static var gotCppDependencies = false;
  356. static function getCppDependencies() {
  357. if (gotCppDependencies) return;
  358. //hxcpp dependencies
  359. switch (systemName) {
  360. case "Linux":
  361. requireAptPackages(["gcc-multilib", "g++-multilib"]);
  362. case "Mac":
  363. //pass
  364. }
  365. //install and build hxcpp
  366. try {
  367. getHaxelibPath("hxcpp");
  368. infoMsg('hxcpp has already been installed.');
  369. } catch(e:Dynamic) {
  370. haxelibInstallGit("HaxeFoundation", "hxcpp", true);
  371. var oldDir = Sys.getCwd();
  372. changeDirectory(getHaxelibPath("hxcpp") + "tools/hxcpp/");
  373. runCommand("haxe", ["compile.hxml"]);
  374. changeDirectory(oldDir);
  375. }
  376. gotCppDependencies = true;
  377. }
  378. static function getJavaDependencies() {
  379. haxelibInstallGit("HaxeFoundation", "hxjava", true);
  380. runCommand("javac", ["-version"]);
  381. }
  382. static function getJSDependencies() {
  383. switch (systemName) {
  384. case "Linux":
  385. if (commandSucceed("node", ["-v"])) {
  386. infoMsg('node has already been installed.');
  387. } else {
  388. requireAptPackages(["nodejs"]);
  389. }
  390. case "Mac":
  391. //pass
  392. }
  393. runCommand("node", ["-v"]);
  394. }
  395. static function getLuaDependencies(jit = false, lua_version = "lua5.2", luarocks_version = "2.3.0") {
  396. switch (systemName){
  397. case "Linux": requireAptPackages(["libpcre3-dev"]);
  398. case "Mac": runCommand("brew", ["install", "pcre"]);
  399. }
  400. var home_dir = Sys.getEnv("HOME");
  401. // the lua paths created by the setup script.
  402. addToPATH('$home_dir/.lua');
  403. addToPATH('$home_dir/.local/bin');
  404. // we need to cd back into the build directory to do some work
  405. var build_dir = Sys.getEnv("TRAVIS_BUILD_DIR");
  406. changeDirectory(build_dir);
  407. // luarocks needs to be in the path
  408. addToPATH('$build_dir/install/luarocks/bin');
  409. if (jit) Sys.putEnv("LUAJIT","yes");
  410. Sys.putEnv("LUAROCKS", luarocks_version);
  411. Sys.putEnv("LUA", lua_version);
  412. // use the helper scripts in .travis. TODO: Refactor as pure haxe?
  413. runCommand("sh", ['${build_dir}/.travis/setenv_lua.sh']);
  414. if (jit){
  415. runCommand("luajit", ["-v"]);
  416. } else {
  417. runCommand("lua", ["-v"]);
  418. }
  419. runCommand("pip", ["install", "--user", "cpp-coveralls"]);
  420. runCommand("luarocks", ["install", "lrexlib-pcre", "2.7.2-1", "--server=https://luarocks.org/dev"]);
  421. runCommand("luarocks", ["install", "luautf8", "--server=https://luarocks.org/dev"]);
  422. // we did user land installs of luarocks and lua. We need to point lua
  423. // to the luarocks install using the luarocks path and env variables
  424. var lua_path = commandResult("luarocks", ["path", "--lr-path"]).stdout.trim();
  425. Sys.putEnv("LUA_PATH", lua_path);
  426. trace(lua_path + " is the value for lua_path");
  427. // step two of the variable setting
  428. var lua_cpath = commandResult("luarocks", ["path", "--lr-cpath"]).stdout.trim();
  429. Sys.putEnv("LUA_CPATH", lua_cpath);
  430. trace(lua_cpath + " is the value for lua_cpath");
  431. // change back to the unit dir for the rest of the tests
  432. changeDirectory(unitDir);
  433. }
  434. static function getCsDependencies() {
  435. switch (systemName) {
  436. case "Linux":
  437. if (commandSucceed("mono", ["--version"]))
  438. infoMsg('mono has already been installed.');
  439. else
  440. requireAptPackages(["mono-devel", "mono-mcs"]);
  441. runCommand("mono", ["--version"]);
  442. case "Mac":
  443. if (commandSucceed("mono", ["--version"]))
  444. infoMsg('mono has already been installed.');
  445. else
  446. runCommand("brew", ["install", "mono"], true);
  447. runCommand("mono", ["--version"]);
  448. case "Windows":
  449. switch (ci) {
  450. case AppVeyor:
  451. addToPATH("C:\\Program Files (x86)\\Mono\\bin");
  452. runCommand("mono", ["--version"]);
  453. case _:
  454. //pass
  455. }
  456. }
  457. haxelibInstallGit("HaxeFoundation", "hxcs", true);
  458. }
  459. static var gotOpenFLDependencies = false;
  460. static function getOpenFLDependencies() {
  461. if (gotOpenFLDependencies) return;
  462. getCppDependencies();
  463. haxelibInstallGit("HaxeFoundation", "format");
  464. haxelibInstallGit("haxenme", "nme");
  465. haxelibInstallGit("haxenme", "nme-dev");
  466. haxelibInstallGit("openfl", "svg");
  467. haxelibInstallGit("openfl", "lime");
  468. haxelibInstallGit("openfl", "lime-tools");
  469. haxelibInstallGit("openfl", "openfl-native");
  470. haxelibInstallGit("openfl", "openfl-html5");
  471. haxelibInstallGit("openfl", "openfl");
  472. switch (systemName) {
  473. case "Linux":
  474. haxelibRun(["openfl", "rebuild", "linux"]);
  475. case "Mac":
  476. haxelibRun(["openfl", "rebuild", "mac"]);
  477. }
  478. haxelibRun(["openfl", "rebuild", "tools"]);
  479. gotOpenFLDependencies = true;
  480. }
  481. /**
  482. Install python and return the names of the installed pythons.
  483. */
  484. static function getPythonDependencies():Array<String> {
  485. switch (systemName) {
  486. case "Linux":
  487. if (commandSucceed("python3", ["-V"]))
  488. infoMsg('python3 has already been installed.');
  489. else
  490. requireAptPackages(["python3"]);
  491. runCommand("python3", ["-V"]);
  492. var pypy = "pypy3";
  493. if (commandSucceed(pypy, ["-V"])) {
  494. infoMsg('pypy3 has already been installed.');
  495. } else {
  496. var pypyVersion = "pypy3-2.4.0-linux64";
  497. runCommand("wget", ['https://bitbucket.org/pypy/pypy/downloads/${pypyVersion}.tar.bz2'], true);
  498. runCommand("tar", ["-xf", '${pypyVersion}.tar.bz2']);
  499. pypy = FileSystem.fullPath('${pypyVersion}/bin/pypy3');
  500. }
  501. runCommand(pypy, ["-V"]);
  502. return ["python3", pypy];
  503. case "Mac":
  504. if (commandSucceed("python3", ["-V"]))
  505. infoMsg('python3 has already been installed.');
  506. else
  507. runCommand("brew", ["install", "python3"], true);
  508. runCommand("python3", ["-V"]);
  509. if (commandSucceed("pypy3", ["-V"]))
  510. infoMsg('pypy3 has already been installed.');
  511. else
  512. runCommand("brew", ["install", "pypy3"], true);
  513. runCommand("pypy3", ["-V"]);
  514. return ["python3", "pypy3"];
  515. case "Windows":
  516. if (commandSucceed("python3", ["-V"]))
  517. infoMsg('python3 has already been installed.');
  518. else
  519. throw "please install python 3.x and make it available as python3 in PATH";
  520. runCommand("python3", ["-V"]);
  521. return ["python3"];
  522. }
  523. return [];
  524. }
  525. static var ci(default, never):Null<Ci> =
  526. if (Sys.getEnv("TRAVIS") == "true")
  527. TravisCI;
  528. else if (Sys.getEnv("APPVEYOR") == "True")
  529. AppVeyor;
  530. else
  531. null;
  532. static var systemName(default, never) = Sys.systemName();
  533. static var cwd(default, never) = Sys.getCwd();
  534. static var repoDir(default, never) = FileSystem.fullPath("..") + "/";
  535. static var unitDir(default, never) = cwd + "unit/";
  536. static var sysDir(default, never) = cwd + "sys/";
  537. static var optDir(default, never) = cwd + "optimization/";
  538. static var miscDir(default, never) = cwd + "misc/";
  539. static var displayDir(default, never) = cwd + "display/";
  540. static var gitInfo(get, null):{repo:String, branch:String, commit:String, timestamp:Float, date:String};
  541. static var success(default, null) = true;
  542. static function get_gitInfo() return if (gitInfo != null) gitInfo else gitInfo = {
  543. repo: switch (ci) {
  544. case TravisCI:
  545. Sys.getEnv("TRAVIS_REPO_SLUG");
  546. case AppVeyor:
  547. Sys.getEnv("APPVEYOR_PROJECT_SLUG");
  548. case _:
  549. commandResult("git", ["config", "--get", "remote.origin.url"]).stdout.trim();
  550. },
  551. branch: switch (ci) {
  552. case TravisCI:
  553. Sys.getEnv("TRAVIS_BRANCH");
  554. case AppVeyor:
  555. Sys.getEnv("APPVEYOR_REPO_BRANCH");
  556. case _:
  557. commandResult("git", ["rev-parse", "--abbrev-ref", "HEAD"]).stdout.trim();
  558. },
  559. commit: commandResult("git", ["rev-parse", "HEAD"]).stdout.trim(),
  560. timestamp: Std.parseFloat(commandResult("git", ["show", "-s", "--format=%ct", "HEAD"]).stdout),
  561. date: {
  562. var gitTime = commandResult("git", ["show", "-s", "--format=%ct", "HEAD"]).stdout;
  563. var tzd = {
  564. var z = Date.fromTime(0);
  565. z.getHours() * 60 * 60 * 1000 + z.getMinutes() * 60 * 1000;
  566. }
  567. // make time in the UTC time zone
  568. var time = Date.fromTime(Std.parseFloat(gitTime) * 1000 - tzd);
  569. DateTools.format(time, "%FT%TZ");
  570. }
  571. }
  572. static var haxeVer(default, never) = {
  573. var haxe_ver = haxe.macro.Compiler.getDefine("haxe_ver");
  574. switch (haxe_ver.split(".")) {
  575. case [major]:
  576. major;
  577. case [major, minor] if (minor.length == 1):
  578. '${major}.${minor}';
  579. case [major, minor] if (minor.length > 1):
  580. var minor = minor.charAt(0);
  581. var patch = Std.parseInt(minor.substr(1));
  582. '${major}.${minor}.${patch}';
  583. case _:
  584. throw haxe_ver;
  585. }
  586. }
  587. static var haxeVerFull(default, never) = {
  588. var ver = haxeVer.split(".");
  589. while (ver.length < 3) {
  590. ver.push("0");
  591. }
  592. ver.join(".");
  593. }
  594. static function deploy():Void {
  595. if (
  596. Sys.getEnv("DEPLOY") != null
  597. ) {
  598. changeDirectory(repoDir);
  599. // generate doc
  600. runCommand("make", ["-s", "install_dox"]);
  601. runCommand("make", ["-s", "package_doc"]);
  602. // deployBintray();
  603. deployApiDoc();
  604. deployPPA();
  605. }
  606. }
  607. static function deployBintray():Void {
  608. if (
  609. Sys.getEnv("BINTRAY") != null &&
  610. Sys.getEnv("BINTRAY_USERNAME") != null &&
  611. Sys.getEnv("BINTRAY_API_KEY") != null
  612. ) {
  613. // generate bintray config
  614. var tpl = new Template(File.getContent("extra/bintray.tpl.json"));
  615. var compatDate = ~/[^0-9]/g.replace(gitInfo.date, "");
  616. var json = tpl.execute({
  617. packageSubject: {
  618. var sub = Sys.getEnv("BINTRAY_SUBJECT");
  619. sub != null ? sub : Sys.getEnv("BINTRAY_USERNAME");
  620. },
  621. os: systemName.toLowerCase(),
  622. versionName: '${haxeVer}+${compatDate}.${gitInfo.commit.substr(0,7)}',
  623. versionDesc: "Automated CI build.",
  624. gitRepo: gitInfo.repo,
  625. gitBranch: gitInfo.branch,
  626. gitCommit: gitInfo.commit,
  627. gitDate: gitInfo.date,
  628. });
  629. var path = "extra/bintray.json";
  630. File.saveContent("extra/bintray.json", json);
  631. infoMsg("saved " + FileSystem.absolutePath(path) + " with content:");
  632. Sys.println(json);
  633. }
  634. }
  635. /**
  636. Deploy doc to api.haxe.org.
  637. */
  638. static function deployApiDoc():Void {
  639. if (
  640. gitInfo.branch == "development" &&
  641. Sys.getEnv("DEPLOY") != null &&
  642. Sys.getEnv("deploy_key_decrypt") != null
  643. ) {
  644. // setup deploy_key
  645. runCommand("openssl aes-256-cbc -k \"$deploy_key_decrypt\" -in extra/deploy_key.enc -out extra/deploy_key -d");
  646. runCommand("chmod 600 extra/deploy_key");
  647. runCommand("ssh-add extra/deploy_key");
  648. runCommand("make", ["-s", "deploy_doc"]);
  649. }
  650. }
  651. /**
  652. Deploy source package to ppa:haxe/snapshots.
  653. */
  654. static function deployPPA():Void {
  655. if (
  656. gitInfo.branch == "development" &&
  657. Sys.getEnv("DEPLOY") != null &&
  658. Sys.getEnv("haxeci_decrypt") != null
  659. ) {
  660. // setup deb info
  661. runCommand("git config --global user.name \"${DEBFULLNAME}\"");
  662. runCommand("git config --global user.email \"${DEBEMAIL}\"");
  663. // setup haxeci_ssh
  664. runCommand("openssl aes-256-cbc -k \"$haxeci_decrypt\" -in extra/haxeci_ssh.enc -out extra/haxeci_ssh -d");
  665. runCommand("chmod 600 extra/haxeci_ssh");
  666. runCommand("ssh-add extra/haxeci_ssh");
  667. // setup haxeci_sec.gpg
  668. runCommand("openssl aes-256-cbc -k \"$haxeci_decrypt\" -in extra/haxeci_sec.gpg.enc -out extra/haxeci_sec.gpg -d");
  669. runCommand("gpg --allow-secret-key-import --import extra/haxeci_sec.gpg");
  670. runCommand("sudo apt-get install devscripts git-buildpackage ubuntu-dev-tools dh-make -y");
  671. var compatDate = ~/[^0-9]/g.replace(gitInfo.date, "");
  672. var SNAPSHOT_VERSION = '${haxeVerFull}+1SNAPSHOT${compatDate}+${gitInfo.commit.substr(0,7)}';
  673. runCommand('cp out/haxe*_src.tar.gz "../haxe_${SNAPSHOT_VERSION}.orig.tar.gz"');
  674. changeDirectory("..");
  675. runCommand("git clone https://github.com/HaxeFoundation/haxe-debian.git");
  676. changeDirectory("haxe-debian");
  677. runCommand("git checkout upstream");
  678. runCommand("git checkout next");
  679. runCommand('gbp import-orig "../haxe_${SNAPSHOT_VERSION}.orig.tar.gz" -u "${SNAPSHOT_VERSION}" --debian-branch=next');
  680. runCommand('dch -v "1:${SNAPSHOT_VERSION}-1" --urgency low "snapshot build"');
  681. runCommand("debuild -S -sa");
  682. runCommand("backportpackage -d xenial --upload ${PPA} --yes ../haxe_*.dsc");
  683. runCommand("backportpackage -d wily --upload ${PPA} --yes ../haxe_*.dsc");
  684. runCommand("backportpackage -d vivid --upload ${PPA} --yes ../haxe_*.dsc");
  685. runCommand("backportpackage -d trusty --upload ${PPA} --yes ../haxe_*.dsc");
  686. runCommand("git checkout debian/changelog");
  687. runCommand("git merge -X ours --no-edit origin/next-precise");
  688. runCommand('dch -v "1:${SNAPSHOT_VERSION}-1" --urgency low "snapshot build"');
  689. runCommand("debuild -S -sa");
  690. runCommand("backportpackage -d precise --upload ${PPA} --yes ../haxe_*.dsc");
  691. }
  692. }
  693. static function main():Void {
  694. Sys.putEnv("OCAMLRUNPARAM", "b");
  695. var tests:Array<TEST> = switch (Sys.getEnv("TEST")) {
  696. case null:
  697. [Macro];
  698. case env:
  699. [for (v in env.split(",")) v.trim().toLowerCase()];
  700. }
  701. Sys.println('Going to test: $tests');
  702. for (test in tests) {
  703. switch (ci) {
  704. case TravisCI:
  705. Sys.println('travis_fold:start:test-${test}');
  706. case _:
  707. //pass
  708. }
  709. infoMsg('test $test');
  710. var success = true;
  711. try {
  712. changeDirectory(unitDir);
  713. var args = switch (ci) {
  714. case TravisCI:
  715. ["-D","travis"];
  716. case AppVeyor:
  717. ["-D","appveyor"];
  718. case _:
  719. [];
  720. }
  721. switch (test) {
  722. case Macro:
  723. runCommand("haxe", ["compile-macro.hxml"].concat(args));
  724. changeDirectory(displayDir);
  725. runCommand("haxe", ["build.hxml"]);
  726. changeDirectory(miscDir);
  727. getCsDependencies();
  728. getPythonDependencies();
  729. runCommand("haxe", ["compile.hxml"]);
  730. changeDirectory(sysDir);
  731. runCommand("haxe", ["compile-macro.hxml"]);
  732. runCommand("haxe", ["compile-each.hxml", "--run", "Main"]);
  733. case Neko:
  734. runCommand("haxe", ["compile-neko.hxml", "-D", "dump", "-D", "dump_ignore_var_ids"].concat(args));
  735. runCommand("neko", ["bin/unit.n"]);
  736. changeDirectory(sysDir);
  737. runCommand("haxe", ["compile-neko.hxml"]);
  738. runCommand("neko", ["bin/neko/sys.n"]);
  739. case Php:
  740. getPhpDependencies();
  741. runCommand("haxe", ["compile-php.hxml"].concat(args));
  742. runCommand("php", ["bin/php/index.php"]);
  743. changeDirectory(sysDir);
  744. runCommand("haxe", ["compile-php.hxml"]);
  745. runCommand("php", ["bin/php/Main/index.php"]);
  746. case Python:
  747. var pys = getPythonDependencies();
  748. runCommand("haxe", ["compile-python.hxml"].concat(args));
  749. for (py in pys) {
  750. runCommand(py, ["bin/unit.py"]);
  751. }
  752. changeDirectory(sysDir);
  753. runCommand("haxe", ["compile-python.hxml"]);
  754. for (py in pys) {
  755. runCommand(py, ["bin/python/sys.py"]);
  756. }
  757. changeDirectory(miscDir + "pythonImport");
  758. runCommand("haxe", ["compile.hxml"]);
  759. for (py in pys) {
  760. runCommand(py, ["test.py"]);
  761. }
  762. case Lua:
  763. getLuaDependencies();
  764. runCommand("haxe", ["compile-lua.hxml"].concat(args));
  765. runCommand("lua", ["bin/unit.lua"]);
  766. case Cpp:
  767. getCppDependencies();
  768. runCommand("haxe", ["compile-cpp.hxml", "-D", "HXCPP_M32"].concat(args));
  769. runCpp("bin/cpp/TestMain-debug", []);
  770. switch (ci) {
  771. case AppVeyor:
  772. //save time...
  773. case _:
  774. runCommand("rm", ["-rf", "cpp"]);
  775. runCommand("haxe", ["compile-cpp.hxml", "-D", "HXCPP_M64"].concat(args));
  776. runCpp("bin/cpp/TestMain-debug", []);
  777. runCommand("haxe", ["compile-cppia-host.hxml"]);
  778. runCommand("haxe", ["compile-cppia.hxml"]);
  779. runCpp("bin/cppia/Host-debug", ["bin/unit.cppia"]);
  780. }
  781. changeDirectory(sysDir);
  782. runCommand("haxe", ["compile-cpp.hxml"]);
  783. runCpp("bin/cpp/Main-debug", []);
  784. // if (Sys.systemName() == "Mac")
  785. // {
  786. // changeDirectory(miscDir + "cppObjc");
  787. // runCommand("haxe", ["build.hxml"]);
  788. // runCpp("bin/TestObjc-debug");
  789. // }
  790. case Js:
  791. getJSDependencies();
  792. var jsOutputs = [
  793. for (es3 in [[], ["-D", "js-es=3"]])
  794. for (unflatten in [[], ["-D", "js-unflatten"]])
  795. for (classic in [[], ["-D", "js-classic"]])
  796. {
  797. var extras = args.concat(es3).concat(unflatten).concat(classic);
  798. runCommand("haxe", ["compile-js.hxml"].concat(extras));
  799. var output = if (extras.length > 0) {
  800. "bin/js/" + extras.join("") + "/unit.js";
  801. } else {
  802. "bin/js/default/unit.js";
  803. }
  804. var outputDir = Path.directory(output);
  805. if (!FileSystem.exists(outputDir)) {
  806. FileSystem.createDirectory(outputDir);
  807. }
  808. FileSystem.rename("bin/unit.js", output);
  809. FileSystem.rename("bin/unit.js.map", output + ".map");
  810. runCommand("node", ["-e", "require('./" + output + "').unit.TestMain.nodejsMain();"]);
  811. output;
  812. }
  813. ];
  814. var env = Sys.environment();
  815. if (
  816. env.exists("SAUCE") &&
  817. env.exists("SAUCE_USERNAME") &&
  818. env.exists("SAUCE_ACCESS_KEY")
  819. ) {
  820. // sauce-connect should have been started
  821. // var scVersion = "sc-4.3-linux";
  822. // runCommand("wget", ['https://saucelabs.com/downloads/${scVersion}.tar.gz'], true);
  823. // runCommand("tar", ["-xf", '${scVersion}.tar.gz']);
  824. // //start sauce-connect
  825. // var scReadyFile = "sauce-connect-ready-" + Std.random(100);
  826. // var sc = new Process('${scVersion}/bin/sc', [
  827. // "-i", Sys.getEnv("TRAVIS_JOB_NUMBER"),
  828. // "-f", scReadyFile
  829. // ]);
  830. // while(!FileSystem.exists(scReadyFile)) {
  831. // Sys.sleep(0.5);
  832. // }
  833. runCommand("npm", ["install", "wd", "q"], true);
  834. haxelibInstall("hxnodejs");
  835. runCommand("haxe", ["compile-saucelabs-runner.hxml"]);
  836. var server = new Process("nekotools", ["server"]);
  837. runCommand("node", ["bin/RunSauceLabs.js"].concat([for (js in jsOutputs) "unit-js.html?js=" + js.urlEncode()]));
  838. server.close();
  839. // sc.close();
  840. }
  841. infoMsg("Test optimization:");
  842. changeDirectory(optDir);
  843. runCommand("haxe", ["run.hxml"]);
  844. case Java:
  845. getJavaDependencies();
  846. runCommand("haxe", ["compile-java.hxml"].concat(args));
  847. runCommand("java", ["-jar", "bin/java/TestMain-Debug.jar"]);
  848. runCommand("haxe", ["compile-java.hxml","-dce","no"].concat(args));
  849. runCommand("java", ["-jar", "bin/java/TestMain-Debug.jar"]);
  850. changeDirectory(sysDir);
  851. runCommand("haxe", ["compile-java.hxml"]);
  852. runCommand("java", ["-jar", "bin/java/Main-Debug.jar"]);
  853. infoMsg("Testing java-lib extras");
  854. changeDirectory('$unitDir/bin');
  855. runCommand("git", ["clone", "https://github.com/waneck/java-lib-tests.git", "--depth", "1"], true);
  856. for (dir in FileSystem.readDirectory('java-lib-tests'))
  857. {
  858. var path = 'java-lib-tests/$dir';
  859. if (FileSystem.isDirectory(path)) for (file in FileSystem.readDirectory(path))
  860. {
  861. if (file.endsWith('.hxml'))
  862. {
  863. runCommand("haxe", ["--cwd",'java-lib-tests/$dir',file]);
  864. }
  865. }
  866. }
  867. case Cs:
  868. getCsDependencies();
  869. var compl = switch [ci, systemName] {
  870. case [TravisCI, "Linux"]:
  871. "-travis";
  872. case _:
  873. "";
  874. };
  875. for (fastcast in [[], ["-D", "fast_cast"]])
  876. for (noroot in [[], ["-D", "no_root"]])
  877. for (erasegenerics in [[], ["-D", "erase_generics"]])
  878. {
  879. var extras = fastcast.concat(erasegenerics).concat(noroot);
  880. runCommand("haxe", ['compile-cs$compl.hxml'].concat(extras));
  881. runCs("bin/cs/bin/TestMain-Debug.exe");
  882. runCommand("haxe", ['compile-cs-unsafe$compl.hxml'].concat(extras));
  883. runCs("bin/cs_unsafe/bin/TestMain-Debug.exe");
  884. }
  885. runCommand("haxe", ['compile-cs$compl.hxml','-dce','no']);
  886. runCs("bin/cs/bin/TestMain-Debug.exe");
  887. changeDirectory(sysDir);
  888. runCommand("haxe", ["compile-cs.hxml",'-D','fast_cast']);
  889. runCs("bin/cs/bin/Main-Debug.exe", []);
  890. changeDirectory(miscDir + "csTwoLibs");
  891. for (i in 1...5)
  892. {
  893. runCommand("haxe", ['compile-$i.hxml','-D','fast_cast']);
  894. runCs("bin/main/bin/Main.exe");
  895. }
  896. case Flash9:
  897. setupFlashPlayerDebugger();
  898. runCommand("haxe", ["compile-flash9.hxml", "-D", "fdb", "-D", "dump", "-D", "dump_ignore_var_ids"].concat(args));
  899. var success = runFlash("bin/unit9.swf");
  900. if (!success)
  901. fail();
  902. case As3:
  903. setupFlashPlayerDebugger();
  904. //setup flex sdk
  905. if (commandSucceed("mxmlc", ["--version"])) {
  906. infoMsg('mxmlc has already been installed.');
  907. } else {
  908. var flexVersion = "4.14.1";
  909. runCommand("wget", ['http://archive.apache.org/dist/flex/${flexVersion}/binaries/apache-flex-sdk-${flexVersion}-bin.tar.gz'], true);
  910. runCommand("tar", ["-xf", 'apache-flex-sdk-${flexVersion}-bin.tar.gz', "-C", Sys.getEnv("HOME")]);
  911. var flexsdkPath = Sys.getEnv("HOME") + '/apache-flex-sdk-${flexVersion}-bin';
  912. addToPATH(flexsdkPath + "/bin");
  913. var playerglobalswcFolder = flexsdkPath + "/player";
  914. FileSystem.createDirectory(playerglobalswcFolder + "/11.1");
  915. runCommand("wget", ["-nv", "http://download.macromedia.com/get/flashplayer/updaters/11/playerglobal11_1.swc", "-O", playerglobalswcFolder + "/11.1/playerglobal.swc"], true);
  916. File.saveContent(flexsdkPath + "/env.properties", 'env.PLAYERGLOBAL_HOME=$playerglobalswcFolder');
  917. runCommand("mxmlc", ["--version"]);
  918. }
  919. runCommand("haxe", ["compile-as3.hxml", "-D", "fdb"].concat(args));
  920. var success = runFlash("bin/unit9_as3.swf");
  921. if (!success)
  922. fail();
  923. case Hl:
  924. runCommand("haxe", ["compile-hl.hxml"], false, true);
  925. case ThirdParty:
  926. getPhpDependencies();
  927. getJavaDependencies();
  928. getJSDependencies();
  929. getCsDependencies();
  930. getPythonDependencies();
  931. getCppDependencies();
  932. //getOpenFLDependencies();
  933. //testPolygonalDs();
  934. // if (systemName == "Linux") testFlambe(); //#3439
  935. testHxTemplo();
  936. testMUnit();
  937. testHaxeQuake();
  938. //testOpenflSamples();
  939. //testFlixelDemos();
  940. case t:
  941. throw "unknown target: " + t;
  942. }
  943. } catch(f:Failure) {
  944. success = false;
  945. }
  946. switch (ci) {
  947. case TravisCI:
  948. Sys.println('travis_fold:end:test-${test}');
  949. case _:
  950. //pass
  951. }
  952. if (success) {
  953. successMsg('test ${test} succeeded');
  954. } else {
  955. failMsg('test ${test} failed');
  956. }
  957. }
  958. if (success) {
  959. deploy();
  960. } else {
  961. Sys.exit(1);
  962. }
  963. }
  964. static function testHxTemplo() {
  965. infoMsg("Test hx-templo:");
  966. changeDirectory(unitDir);
  967. haxelibInstallGit("Simn", "hxparse", "development", "src");
  968. haxelibInstallGit("Simn", "hxtemplo");
  969. var buildArgs = [
  970. "-cp", "src",
  971. "-cp", "test",
  972. "-main", "Test",
  973. "-lib", "hxparse",
  974. "-dce", "full"
  975. ];
  976. changeDirectory(getHaxelibPath("hxtemplo") + "..");
  977. runCommand("haxe", ["build.hxml"]);
  978. }
  979. static function testPolygonalDs() {
  980. infoMsg("Test polygonal-ds:");
  981. changeDirectory(unitDir);
  982. haxelibInstallGit("Simn", "ds", "python-support", null, false, "polygonal-ds");
  983. haxelibInstallGit("polygonal", "core", "master", "src", false, "polygonal-core");
  984. haxelibInstallGit("polygonal", "printf", "master", "src", false, "polygonal-printf");
  985. changeDirectory(getHaxelibPath("polygonal-ds"));
  986. runCommand("haxe", ["build.hxml"]);
  987. runCommand("python3", ["unit.py"]);
  988. runCommand("node", ["unit.js"]);
  989. }
  990. static function testMUnit() {
  991. infoMsg("Test MUnit:");
  992. changeDirectory(unitDir);
  993. haxelibInstallGit("massiveinteractive", "mconsole", "master", "src");
  994. haxelibInstallGit("massiveinteractive", "MassiveCover", "master", "src", false, "mcover");
  995. haxelibInstallGit("massiveinteractive", "MassiveLib", "master", "src", false, "mlib");
  996. haxelibInstallGit("massiveinteractive", "MassiveUnit", "2.1.2", "src", false, "munit");
  997. changeDirectory(Path.join([getHaxelibPath("munit"), "..", "tool"]));
  998. runCommand("haxe", ["build.hxml"]);
  999. haxelibRun(["munit", "test", "-result-exit-code", "-neko"], true);
  1000. changeDirectory("../");
  1001. haxelibRun(["munit", "test", "-result-exit-code", "-neko"], true);
  1002. }
  1003. static function testHaxeQuake() {
  1004. infoMsg("Test HaxeQuake:");
  1005. changeDirectory(unitDir);
  1006. runCommand("git", ["clone", "https://github.com/nadako/HaxeQuake"]);
  1007. changeDirectory("HaxeQuake/Client");
  1008. runCommand("haxe", ["build.hxml"]);
  1009. }
  1010. static function testFlambe() {
  1011. infoMsg("Test Flambe:");
  1012. changeDirectory(unitDir);
  1013. runCommand("git", ["clone", "https://github.com/aduros/flambe"]);
  1014. runCommand("sh", ["flambe/bin/run-travis"]);
  1015. }
  1016. //static function testOpenflSamples() {
  1017. //infoMsg("Test OpenFL Samples:");
  1018. //
  1019. //changeDirectory(unitDir);
  1020. //
  1021. //haxelibInstallGit("jgranick", "actuate");
  1022. //haxelibInstallGit("jgranick", "box2d");
  1023. //haxelibInstallGit("jgranick", "layout");
  1024. //haxelibInstallGit("openfl", "swf");
  1025. //haxelibInstallGit("openfl", "openfl-samples");
  1026. //
  1027. //var path = getHaxelibPath("openfl-samples");
  1028. //var old = Sys.getEnv("pwd");
  1029. //Sys.putEnv("pwd", path);
  1030. //parseTravisFile(haxe.io.Path.join([path, ".travis.yml"]), true);
  1031. //if (old != null) {
  1032. //Sys.putEnv("pwd", old);
  1033. //}
  1034. //}
  1035. static function testFlixelDemos() {
  1036. infoMsg("Test Flixel Demos:");
  1037. changeDirectory(unitDir);
  1038. getOpenFLDependencies();
  1039. haxelibInstall("systools");
  1040. haxelibInstall("spinehx");
  1041. haxelibInstall("nape");
  1042. haxelibInstall("task");
  1043. haxelibInstallGit("larsiusprime", "firetongue");
  1044. haxelibInstallGit("YellowAfterLife", "openfl-bitfive");
  1045. haxelibInstallGit("HaxeFlixel", "flixel");
  1046. haxelibInstallGit("HaxeFlixel", "flixel-addons");
  1047. haxelibInstallGit("HaxeFlixel", "flixel-ui");
  1048. haxelibInstallGit("HaxeFlixel", "flixel-demos");
  1049. haxelibInstallGit("HaxeFlixel", "flixel-tools");
  1050. haxelibRun(["flixel-tools", "testdemos", "-flash"]);
  1051. haxelibRun(["flixel-tools", "testdemos", "-neko"]);
  1052. haxelibRun(["flixel-tools", "testdemos", "-html5"]);
  1053. }
  1054. }