Deployment.hx 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. package runci;
  2. import runci.Config.*;
  3. import runci.System.*;
  4. import sys.io.File;
  5. import sys.FileSystem;
  6. import haxe.*;
  7. using StringTools;
  8. class Deployment {
  9. static var S3_HXBUILDS_ADDR(default, null) = 's3://hxbuilds/builds/haxe';
  10. static var gitInfo(get, null):{repo:String, branch:String, commit:String, timestamp:Float, date:String};
  11. static function get_gitInfo() return if (gitInfo != null) gitInfo else gitInfo = {
  12. repo: switch (ci) {
  13. case TravisCI:
  14. Sys.getEnv("TRAVIS_REPO_SLUG");
  15. case AppVeyor:
  16. Sys.getEnv("APPVEYOR_PROJECT_SLUG");
  17. case AzurePipelines:
  18. Sys.getEnv("AZURE_PIPELINES_REPO_URL");
  19. case _:
  20. commandResult("git", ["config", "--get", "remote.origin.url"]).stdout.trim();
  21. },
  22. branch: switch (ci) {
  23. case TravisCI:
  24. Sys.getEnv("TRAVIS_BRANCH");
  25. case AppVeyor:
  26. Sys.getEnv("APPVEYOR_REPO_BRANCH");
  27. case AzurePipelines:
  28. Sys.getEnv("AZURE_PIPELINES_BRANCH");
  29. case _:
  30. commandResult("git", ["rev-parse", "--abbrev-ref", "HEAD"]).stdout.trim();
  31. },
  32. commit: commandResult("git", ["rev-parse", "HEAD"]).stdout.trim(),
  33. timestamp: Std.parseFloat(commandResult("git", ["show", "-s", "--format=%ct", "HEAD"]).stdout),
  34. date: {
  35. var gitTime = commandResult("git", ["show", "-s", "--format=%ct", "HEAD"]).stdout;
  36. var tzd = {
  37. var z = Date.fromTime(0);
  38. z.getHours() * 60 * 60 * 1000 + z.getMinutes() * 60 * 1000;
  39. }
  40. // make time in the UTC time zone
  41. var time = Date.fromTime(Std.parseFloat(gitTime) * 1000 - tzd);
  42. DateTools.format(time, "%Y-%m-%dT%H:%M:%SZ");
  43. }
  44. }
  45. static function isDeployNightlies() {
  46. return
  47. Sys.getEnv("DEPLOY_NIGHTLIES") != null &&
  48. (gitInfo.branch == "development" || gitInfo.branch == "master" || gitInfo.branch == "deploy-test");
  49. }
  50. static function deployBintray():Void {
  51. if (
  52. Sys.getEnv("BINTRAY") != null &&
  53. Sys.getEnv("BINTRAY_USERNAME") != null &&
  54. Sys.getEnv("BINTRAY_API_KEY") != null
  55. ) {
  56. // generate bintray config
  57. var tpl = new Template(File.getContent("extra/bintray.tpl.json"));
  58. var compatDate = ~/[^0-9]/g.replace(gitInfo.date, "");
  59. var json = tpl.execute({
  60. packageSubject: {
  61. var sub = Sys.getEnv("BINTRAY_SUBJECT");
  62. sub != null ? sub : Sys.getEnv("BINTRAY_USERNAME");
  63. },
  64. os: systemName.toLowerCase(),
  65. versionName: '${haxeVer}+${compatDate}.${gitInfo.commit.substr(0,7)}',
  66. versionDesc: "Automated CI build.",
  67. gitRepo: gitInfo.repo,
  68. gitBranch: gitInfo.branch,
  69. gitCommit: gitInfo.commit,
  70. gitDate: gitInfo.date,
  71. });
  72. var path = "extra/bintray.json";
  73. File.saveContent("extra/bintray.json", json);
  74. infoMsg("saved " + FileSystem.absolutePath(path) + " with content:");
  75. Sys.println(json);
  76. }
  77. }
  78. static function isDeployApiDocsRequired() {
  79. return
  80. Sys.getEnv("DEPLOY_API_DOCS") != null &&
  81. (
  82. gitInfo.branch == "development" ||
  83. switch(Sys.getEnv("TRAVIS_TAG")) {
  84. case null, _.trim() => "":
  85. false;
  86. case tag:
  87. true;
  88. }
  89. );
  90. }
  91. /**
  92. Deploy doc to api.haxe.org.
  93. */
  94. static function deployApiDoc():Void {
  95. changeDirectory(repoDir);
  96. runCommand("make", ["xmldoc"]);
  97. File.saveContent("extra/doc/info.json", Json.stringify({
  98. "commit": gitInfo.commit,
  99. "branch": gitInfo.branch,
  100. }));
  101. switch (Sys.getEnv("GHP_REMOTE")) { // should be in the form of https://[email protected]/account/repo.git
  102. case null:
  103. infoMsg('Missing GHP_REMOTE, skip api doc deploy.');
  104. case remoteRepo:
  105. var localRepo = "extra/api.haxe.org";
  106. runCommand("git", ["clone", remoteRepo, localRepo]);
  107. runCommand("haxe", ["--cwd", localRepo, "--run", "ImportXml", FileSystem.absolutePath("extra/doc")]);
  108. }
  109. }
  110. static function cleanup32BitDlls()
  111. {
  112. infoMsg('Cleaning up the 32-bit DLLS');
  113. cleanup32BitDll('zlib1.dll');
  114. }
  115. static function cleanup32BitDll(name:String)
  116. {
  117. var cygRoot = Sys.getEnv("CYG_ROOT");
  118. if (cygRoot != null) {
  119. while (true)
  120. {
  121. var proc = new sys.io.Process('$cygRoot/bin/bash', ['-lc', '/usr/bin/cygpath -w "`which $name`"']);
  122. var out = proc.stdout.readAll().toString().trim();
  123. var err = proc.stderr.readAll().toString().trim();
  124. if (proc.exitCode() == 0)
  125. {
  126. if (!is64BitDll(out))
  127. {
  128. infoMsg('Deleting the file $out because it is a 32-bit DLL');
  129. sys.FileSystem.deleteFile(out);
  130. } else {
  131. break;
  132. }
  133. } else {
  134. infoMsg('Error while getting the cygpath for $name: $out\n$err');
  135. break; // no more dlls
  136. }
  137. }
  138. } else {
  139. var path = Sys.getEnv('PATH').split(';');
  140. for (base in path)
  141. {
  142. var fullPath = '$base/$name';
  143. if (sys.FileSystem.exists(fullPath) && !is64BitDll(fullPath))
  144. {
  145. infoMsg('Deleting the file $fullPath because it is a 32-bit DLL');
  146. sys.FileSystem.deleteFile(fullPath);
  147. }
  148. }
  149. }
  150. }
  151. static function is64BitDll(path:String)
  152. {
  153. if (!sys.FileSystem.exists(path))
  154. {
  155. throw 'The DLL at path $path was not found';
  156. }
  157. var file = sys.io.File.read(path);
  158. if (file.readByte() != 'M'.code || file.readByte() != 'Z'.code)
  159. {
  160. throw 'The DLL at path $path is invalid: Invalid MZ magic header';
  161. }
  162. file.seek(0x3c, SeekBegin);
  163. var peSigOffset = file.readInt32();
  164. file.seek(peSigOffset, SeekBegin);
  165. if (file.readByte() != 'P'.code || file.readByte() != 'E'.code || file.readByte() != 0 || file.readByte() != 0)
  166. {
  167. throw 'Invalid PE header signature: PE expected';
  168. }
  169. // coff header
  170. file.readString(20);
  171. // pe header
  172. var peKind = file.readUInt16();
  173. file.close();
  174. switch(peKind)
  175. {
  176. case 0x20b: // 64 bit
  177. return true;
  178. case 0x10b: // 32 bit
  179. return false;
  180. case 0x107: // rom
  181. return false;
  182. case _:
  183. throw 'Unknown PE header kind $peKind';
  184. }
  185. }
  186. static function fileExtension(file:String) {
  187. file = haxe.io.Path.withoutDirectory(file);
  188. var idx = file.indexOf('.');
  189. if (idx < 0) {
  190. return '';
  191. } else {
  192. return file.substr(idx);
  193. }
  194. }
  195. /**
  196. Deploy source package to ppa:haxe/snapshots.
  197. */
  198. static function deployPPA():Void {
  199. if (
  200. gitInfo.branch == "development" &&
  201. Sys.getEnv("DEPLOY") != null &&
  202. Sys.getEnv("haxeci_decrypt") != null
  203. ) {
  204. // setup deb info
  205. runCommand("git config --global user.name \"${DEBFULLNAME}\"");
  206. runCommand("git config --global user.email \"${DEBEMAIL}\"");
  207. // setup haxeci_ssh
  208. runCommand("openssl aes-256-cbc -k \"$haxeci_decrypt\" -in extra/haxeci_ssh.enc -out extra/haxeci_ssh -d");
  209. runCommand("chmod 600 extra/haxeci_ssh");
  210. runCommand("ssh-add extra/haxeci_ssh");
  211. // setup haxeci_sec.gpg
  212. runCommand("openssl aes-256-cbc -k \"$haxeci_decrypt\" -in extra/haxeci_sec.gpg.enc -out extra/haxeci_sec.gpg -d");
  213. runCommand("gpg --allow-secret-key-import --import extra/haxeci_sec.gpg");
  214. runCommand("sudo apt-get install devscripts git-buildpackage ubuntu-dev-tools dh-make -y");
  215. var compatDate = ~/[^0-9]/g.replace(gitInfo.date, "");
  216. var SNAPSHOT_VERSION = '${haxeVerFull}+1SNAPSHOT${compatDate}+${gitInfo.commit.substr(0,7)}';
  217. runCommand('cp out/haxe*_src.tar.gz "../haxe_${SNAPSHOT_VERSION}.orig.tar.gz"');
  218. changeDirectory("..");
  219. runCommand("git clone https://github.com/HaxeFoundation/haxe-debian.git");
  220. changeDirectory("haxe-debian");
  221. runCommand("git checkout upstream");
  222. runCommand("git checkout next");
  223. runCommand('gbp import-orig "../haxe_${SNAPSHOT_VERSION}.orig.tar.gz" -u "${SNAPSHOT_VERSION}" --debian-branch=next');
  224. runCommand('dch -v "1:${SNAPSHOT_VERSION}-1" --urgency low "snapshot build"');
  225. runCommand("debuild -S -sa");
  226. runCommand("backportpackage -d yakkety --upload ${PPA} --yes ../haxe_*.dsc");
  227. runCommand("backportpackage -d xenial --upload ${PPA} --yes ../haxe_*.dsc");
  228. runCommand("backportpackage -d vivid --upload ${PPA} --yes ../haxe_*.dsc");
  229. runCommand("backportpackage -d trusty --upload ${PPA} --yes ../haxe_*.dsc");
  230. runCommand("git checkout debian/changelog");
  231. runCommand("git merge -X ours --no-edit origin/next-precise");
  232. runCommand('dch -v "1:${SNAPSHOT_VERSION}-1" --urgency low "snapshot build"');
  233. runCommand("debuild -S -sa");
  234. runCommand("backportpackage -d precise --upload ${PPA} --yes ../haxe_*.dsc");
  235. }
  236. }
  237. static var haxeVer(default, never) = {
  238. var haxe_ver = haxe.macro.Compiler.getDefine("haxe_ver");
  239. switch (haxe_ver.split(".")) {
  240. case [major]:
  241. major;
  242. case [major, minor] if (minor.length == 1):
  243. '${major}.${minor}';
  244. case [major, minor] if (minor.length > 1):
  245. var patch = Std.parseInt(minor.substr(1));
  246. var minor = minor.charAt(0);
  247. '${major}.${minor}.${patch}';
  248. case _:
  249. throw haxe_ver;
  250. }
  251. }
  252. static var haxeVerFull(default, never) = {
  253. var ver = haxeVer.split(".");
  254. while (ver.length < 3) {
  255. ver.push("0");
  256. }
  257. ver.join(".");
  258. }
  259. static public function deploy():Void {
  260. switch (ci) {
  261. case TravisCI:
  262. switch (Sys.getEnv("TRAVIS_PULL_REQUEST")) {
  263. case "false", null:
  264. // not a PR
  265. case _:
  266. infoMsg("Not deploying in PR builds.");
  267. return;
  268. }
  269. case AppVeyor:
  270. switch (Sys.getEnv("APPVEYOR_PULL_REQUEST_NUMBER")) {
  271. case null:
  272. // not a PR
  273. case _:
  274. infoMsg("Not deploying in PR builds.");
  275. return;
  276. }
  277. case _:
  278. // pass
  279. }
  280. if (isDeployApiDocsRequired()) {
  281. deployApiDoc();
  282. } else {
  283. infoMsg("Not deploying API doc");
  284. }
  285. }
  286. }