Deployment.hx 8.3 KB

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