publisher.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. // Dependecies.
  2. const prompt = require('prompt');
  3. const shelljs = require('shelljs');
  4. const fs = require('fs-extra');
  5. const path = require('path');
  6. const rmDir = require("../NodeHelpers/rmDir");
  7. const colorConsole = require("../NodeHelpers/colorConsole");
  8. // CMD Arguments Management.
  9. let doNotBuild = false;
  10. let doNotPublish = false;
  11. // Path management.
  12. process.env.PATH += (path.delimiter + path.join(__dirname, 'node_modules', '.bin'));
  13. // Global Variables.
  14. const config = require("../Config/config.js");
  15. const modules = config.modules.concat(config.viewerModules);
  16. const basePath = config.build.outputDirectory;
  17. const enginePath = path.join(config.core.computed.srcDirectory, "Engines/engine.ts");
  18. /**
  19. * Get Files from folder.
  20. */
  21. const getFiles = function(dir, files_) {
  22. files_ = files_ || [];
  23. var files = fs.readdirSync(dir);
  24. for (var i in files) {
  25. var name = dir + '/' + files[i];
  26. if (fs.statSync(name).isDirectory()) {
  27. getFiles(name, files_);
  28. } else {
  29. files_.push(name);
  30. }
  31. }
  32. return files_;
  33. }
  34. /**
  35. * Update the version in the engine class for Babylon
  36. */
  37. function updateEngineVersion(newVersion) {
  38. colorConsole.log("Updating version in engine.ts to: " + newVersion.green);
  39. let engineContent = fs.readFileSync(enginePath).toString();
  40. let replaced = engineContent.replace(/(public static get Version\(\): string {\s*return ")(.*)(";\s*})/g, "$1" + newVersion + "$3");
  41. fs.writeFileSync(enginePath, replaced);
  42. colorConsole.emptyLine();
  43. }
  44. /**
  45. * Get the version from the engine class for Babylon
  46. */
  47. function getEngineVersion() {
  48. colorConsole.log("Get version from engine.ts");
  49. const engineContent = fs.readFileSync(enginePath).toString();
  50. const versionRegex = new RegExp(`public static get Version\\(\\): string {[\\s\\S]*return "([\\s\\S]*?)";[\\s\\S]*}`, "gm");
  51. const match = versionRegex.exec(engineContent);
  52. if (match && match.length) {
  53. const version = match[1];
  54. colorConsole.log("Version found: " + version.green);
  55. colorConsole.emptyLine();
  56. return version;
  57. }
  58. colorConsole.error("Version not found in engine.ts");
  59. process.exit(1);
  60. }
  61. /**
  62. * Publish a package to npm.
  63. */
  64. function publish(version, packageName, publishPath, public) {
  65. colorConsole.log(' Publishing ' + packageName.blue.bold + " from " + publishPath.cyan);
  66. let tag = "";
  67. // check for alpha or beta
  68. if (version.indexOf('alpha') !== -1 || version.indexOf('beta') !== -1) {
  69. tag = ' --tag preview';
  70. }
  71. //publish the respected package
  72. var cmd = 'npm publish "' + publishPath + '"' + tag;
  73. if (public) {
  74. cmd += " --access public";
  75. }
  76. if (doNotPublish) {
  77. colorConsole.log(" If publishing enabled: " + cmd.yellow);
  78. }
  79. else {
  80. colorConsole.log(" Executing: " + cmd.yellow);
  81. shelljs.exec(cmd);
  82. }
  83. colorConsole.success(' Publishing ' + "OK".green);
  84. }
  85. /**
  86. * Build the folder with Gulp.
  87. */
  88. function buildBabylonJSAndDependencies() {
  89. colorConsole.log("Running gulp compilation");
  90. let exec = shelljs.exec("gulp typescript-libraries --gulpfile ../Gulp/gulpfile.js");
  91. if (exec.code) {
  92. colorConsole.error("Error during compilation, aborting");
  93. process.exit(1);
  94. }
  95. }
  96. /**
  97. * Process ES6 Packages.
  98. */
  99. function processEs6Packages(version) {
  100. config.modules.forEach(moduleName => {
  101. let module = config[moduleName];
  102. let es6Config = module.build.es6;
  103. if (!es6Config) {
  104. return;
  105. }
  106. colorConsole.log("Process " + "ES6".magenta + " Package: " + moduleName.blue.bold);
  107. let distPath = module.computed.distES6Directory;
  108. let packagePath = module.computed.packageES6Directory;
  109. let legacyPackageJson = require(module.computed.packageJSONPath);
  110. colorConsole.log(" Cleanup " + packagePath.cyan);
  111. rmDir(packagePath);
  112. colorConsole.log(" Copy Dist folder " + distPath.cyan + " to " + packagePath.cyan);
  113. fs.copySync(distPath, packagePath);
  114. if (module.build.requiredFiles) {
  115. module.build.requiredFiles.forEach(file => {
  116. let source = path.join(config.computed.rootFolder, file);
  117. let destination = path.join(packagePath, path.basename(file));
  118. colorConsole.log(" Copy required file: ", source.cyan, destination.cyan);
  119. fs.copySync(source, destination);
  120. });
  121. }
  122. if (es6Config.requiredFiles) {
  123. es6Config.requiredFiles.forEach(file => {
  124. let source = path.join(config.computed.rootFolder, file);
  125. let destination = path.join(packagePath, path.basename(file));
  126. colorConsole.log(" Copy es6 required file: ", source.cyan, destination.cyan);
  127. fs.copySync(source, destination);
  128. });
  129. }
  130. let files = getFiles(packagePath)
  131. .map(f => f.replace(packagePath + "/", ""))
  132. .filter(f => f.indexOf("assets/") === -1);
  133. legacyPackageJson.name = es6Config.packageName;
  134. legacyPackageJson.version = version;
  135. legacyPackageJson.main = "index.js";
  136. legacyPackageJson.module = "index.js";
  137. legacyPackageJson.esnext = "index.js";
  138. legacyPackageJson.typings = "index.d.ts";
  139. legacyPackageJson.files = files;
  140. ["dependencies", "peerDependencies", "devDependencies"].forEach(key => {
  141. if (legacyPackageJson[key]) {
  142. let dependencies = legacyPackageJson[key];
  143. legacyPackageJson[key] = {};
  144. Object.keys(dependencies).forEach(packageName => {
  145. if (packageName.indexOf("babylonjs") !== -1) {
  146. colorConsole.log(" Checking Internal Dependency: " + packageName.cyan);
  147. let dependencyName = packageName;
  148. for (var moduleName of modules) {
  149. if (config[moduleName] && config[moduleName].build.umd && config[moduleName].build.umd.packageName === packageName) {
  150. if (config[moduleName].build.es6) {
  151. dependencyName = config[moduleName].build.es6.packageName;
  152. colorConsole.log(" Replace Dependency: " + packageName.cyan + " by " + dependencyName.cyan);
  153. break;
  154. }
  155. }
  156. }
  157. legacyPackageJson[key][dependencyName] = version;
  158. } else if (!module.isCore) {
  159. legacyPackageJson[key][packageName] = dependencies[packageName];
  160. }
  161. });
  162. }
  163. });
  164. // Inject tslib as a dependency
  165. var mainPackageJSONPath = path.join(config.computed.rootFolder, "package.json");
  166. var mainPackageJSON = fs.readJSONSync(mainPackageJSONPath);
  167. var tslibSemver = mainPackageJSON["devDependencies"]["tslib"];
  168. colorConsole.log(" Adding tslib version: ", tslibSemver.yellow);
  169. legacyPackageJson["dependencies"]["tslib"] = tslibSemver;
  170. let packageJSONPath = path.join(packagePath, "package.json");
  171. fs.writeFileSync(packageJSONPath, JSON.stringify(legacyPackageJson, null, 4));
  172. // Do not publish yet.
  173. // publish(version, es6Config.packageName, packagePath, true);
  174. colorConsole.emptyLine();
  175. });
  176. }
  177. /**
  178. * Process Legacy Packages.
  179. */
  180. function processLegacyPackages(version) {
  181. modules.forEach(moduleName => {
  182. let module = config[moduleName];
  183. colorConsole.log("Process " + "UMD".magenta + " Package: " + moduleName.blue.bold);
  184. if (moduleName === "core") {
  185. processLegacyCore(version);
  186. }
  187. else if (moduleName === "viewer") {
  188. processLegacyViewer(module, version);
  189. }
  190. else {
  191. let outputDirectory = module.build.legacyPackageOutputDirectory || module.computed.distDirectory;
  192. if (module.build.requiredFiles) {
  193. module.build.requiredFiles.forEach(file => {
  194. let source = path.join(config.computed.rootFolder, file);
  195. let destination = path.join(outputDirectory, path.basename(file));
  196. colorConsole.log(" Copy required file: ", source.cyan, destination.cyan);
  197. fs.copySync(source, destination);
  198. });
  199. }
  200. let packageJson = require(outputDirectory + '/package.json');
  201. packageJson.version = version;
  202. colorConsole.log(" Update package version to: " + version.green);
  203. if (packageJson.dependencies) {
  204. Object.keys(packageJson.dependencies).forEach(key => {
  205. if (key.indexOf("babylonjs") !== -1) {
  206. packageJson.dependencies[key] = version;
  207. }
  208. });
  209. }
  210. fs.writeFileSync(outputDirectory + '/package.json', JSON.stringify(packageJson, null, 4));
  211. publish(version, moduleName, outputDirectory);
  212. colorConsole.emptyLine();
  213. }
  214. });
  215. }
  216. /**
  217. * Special treatment for legacy viewer.
  218. */
  219. function processLegacyViewer(module, version) {
  220. let projectPath = '../../Viewer';
  221. let buildPath = projectPath + "/build/src/";
  222. if (module.build.requiredFiles) {
  223. module.build.requiredFiles.forEach(file => {
  224. let source = path.join(config.computed.rootFolder, file);
  225. let destination = path.join(buildPath, path.basename(file));
  226. colorConsole.log(" Copy required file: ", source.cyan, destination.cyan);
  227. fs.copySync(source, destination);
  228. });
  229. }
  230. // The viewer needs to be built using tsc on the viewer's main repository
  231. // build the viewer.
  232. colorConsole.log(" Executing " + ('tsc -p ' + projectPath).yellow);
  233. let tscCompile = shelljs.exec('tsc -p ' + projectPath);
  234. if (tscCompile.code !== 0) {
  235. throw new Error("tsc compilation failed");
  236. }
  237. let packageJson = require(buildPath + '/package.json');
  238. let files = getFiles(buildPath).map(f => f.replace(buildPath + "/", "")).filter(f => f.indexOf("assets/") === -1);
  239. packageJson.files = files;
  240. packageJson.version = version;
  241. packageJson.module = "index.js";
  242. packageJson.main = "babylon.viewer.js";
  243. packageJson.typings = "index.d.ts";
  244. fs.writeFileSync(buildPath + '/package.json', JSON.stringify(packageJson, null, 4));
  245. publish(version, "viewer", buildPath);
  246. colorConsole.emptyLine();
  247. }
  248. /**
  249. * Special treatment for legacy core.
  250. */
  251. function processLegacyCore(version) {
  252. let package = {
  253. "name": "core",
  254. "path": "/../../"
  255. };
  256. let packageJson = require('../../package.json');
  257. // make a temporary directory
  258. fs.ensureDirSync(basePath + '/package/');
  259. let files = [
  260. {
  261. path: basePath + "/babylon.d.ts",
  262. objectName: "babylon.d.ts"
  263. },
  264. {
  265. path: basePath + "/babylon.js",
  266. objectName: "babylon.js"
  267. },
  268. {
  269. path: basePath + "/babylon.max.js",
  270. objectName: "babylon.max.js"
  271. },
  272. {
  273. path: basePath + "/babylon.max.js.map",
  274. objectName: "babylon.max.js.map"
  275. },
  276. {
  277. path: basePath + "/Oimo.js",
  278. objectName: "Oimo.js"
  279. },
  280. {
  281. path: basePath + package.path + "readme.md",
  282. objectName: "readme.md"
  283. }
  284. ];
  285. //copy them to the package path
  286. files.forEach(file => {
  287. fs.copySync(file.path, basePath + '/package/' + file.objectName);
  288. });
  289. // update package.json
  290. packageJson.version = version;
  291. colorConsole.log(" Generating file list");
  292. let packageFiles = ["package.json"];
  293. files.forEach(file => {
  294. if (!file.isDir) {
  295. packageFiles.push(file.objectName);
  296. } else {
  297. //todo is it better to read the content and add it? leave it like that ATM
  298. packageFiles.push(file.objectName + "/index.js", file.objectName + "/index.d.ts", file.objectName + "/es6.js")
  299. }
  300. });
  301. colorConsole.log(" Updating package.json");
  302. packageJson.files = packageFiles;
  303. packageJson.main = "babylon.js";
  304. packageJson.typings = "babylon.d.ts";
  305. fs.writeFileSync(basePath + '/package/' + 'package.json', JSON.stringify(packageJson, null, 4));
  306. publish(version, package.name, basePath + '/package/');
  307. // remove package directory
  308. fs.removeSync(basePath + '/package/');
  309. // now update the main package.json
  310. packageJson.files = packageJson.files.map(file => {
  311. if (file !== 'package.json' && file !== 'readme.md') {
  312. return 'dist/preview release/' + file;
  313. } else {
  314. return file;
  315. }
  316. });
  317. packageJson.main = "dist/preview release/babylon.js";
  318. packageJson.typings = "dist/preview release/babylon.d.ts";
  319. fs.writeFileSync('../../package.json', JSON.stringify(packageJson, null, 4));
  320. colorConsole.emptyLine();
  321. }
  322. const createVersion = function(version) {
  323. // Prevent to build for test Cases.
  324. if (!doNotBuild) {
  325. buildBabylonJSAndDependencies();
  326. }
  327. // Create the packages and publish if needed.
  328. processLegacyPackages(version);
  329. // Do not publish es6 yet.
  330. doNotPublish = true;
  331. processEs6Packages(version);
  332. }
  333. /**
  334. * Main function driving the publication.
  335. */
  336. module.exports = function(noBuild, noPublish, askVersion) {
  337. doNotBuild = noBuild;
  338. doNotPublish = noPublish;
  339. if (askVersion) {
  340. prompt.start();
  341. prompt.get(['version'], function (err, result) {
  342. const version = result.version;
  343. // Update the engine version if needed.
  344. if (!version || !version.length) {
  345. colorConsole.error("New version required.");
  346. Process.exit(1);
  347. return;
  348. }
  349. updateEngineVersion(version);
  350. createVersion(version);
  351. // Invite user to tag with the new version.
  352. if (newVersion) {
  353. colorConsole.log("Done, please tag git with " + version);
  354. }
  355. });
  356. }
  357. else {
  358. const version = getEngineVersion();
  359. createVersion(version);
  360. }
  361. };