build.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // @ts-check
  2. const {spawn, execSync} = require('child_process');
  3. const fs = require('fs');
  4. const path = require('path');
  5. const keepAsset = require('./keepAsset');
  6. const {NodeSSH} = require('node-ssh');
  7. const zlib = require('zlib');
  8. const npmCmd = /^win/.test(process.platform) ? 'npm.cmd' : 'npm';
  9. const publicPath = path.join(__dirname, 'public');
  10. const distPath = path.join(__dirname, 'dist');
  11. function readSSHConfig() {
  12. let sshConfig;
  13. try {
  14. sshConfig = JSON.parse(fs.readFileSync(path.join(__dirname, 'ssh.json'), 'utf8'));
  15. } catch(err) {
  16. }
  17. return sshConfig;
  18. }
  19. function copyFiles(source, destination) {
  20. if(!fs.existsSync(destination)) {
  21. fs.mkdirSync(destination);
  22. }
  23. const files = fs.readdirSync(source, {withFileTypes: true});
  24. files.forEach((file) => {
  25. const sourcePath = path.join(source, file.name);
  26. const destinationPath = path.join(destination, file.name);
  27. if(file.isFile()) {
  28. fs.copyFileSync(sourcePath, destinationPath);
  29. } else if(file.isDirectory()) {
  30. copyFiles(sourcePath, destinationPath);
  31. }
  32. });
  33. }
  34. function clearOldFiles() {
  35. const bundleFiles = fs.readdirSync(distPath);
  36. const files = fs.readdirSync(publicPath, {withFileTypes: true});
  37. files.forEach((file) => {
  38. if(file.isDirectory() ||
  39. bundleFiles.some((bundleFile) => bundleFile === file.name) ||
  40. keepAsset(file.name)) {
  41. return;
  42. }
  43. fs.unlinkSync(path.join(publicPath, file.name));
  44. });
  45. }
  46. function changeVersion(langVersion) {
  47. const version = process.argv[2] || 'same';
  48. const changelog = process.argv[3] || 'same';
  49. const child = spawn(npmCmd, ['run', 'change-version', version, changelog, langVersion], {shell: true});
  50. child.stdout.on('data', (chunk) => {
  51. console.log(chunk.toString());
  52. });
  53. return new Promise((resolve, reject) => {
  54. child.on('close', (code) => {
  55. if(code != 0) {
  56. reject(new Error('Failed to change version'));
  57. } else {
  58. resolve();
  59. }
  60. });
  61. });
  62. }
  63. function applyNewLang() {
  64. const child = spawn(npmCmd, ['run', 'apply-new-lang'], {shell: true});
  65. let data = '';
  66. child.stdout.on('data', (chunk) => {
  67. data += chunk.toString();
  68. });
  69. return new Promise((resolve, reject) => {
  70. child.on('close', (code) => {
  71. if(code != 0) {
  72. reject(new Error('Failed to apply new lang'));
  73. } else {
  74. const version = +data.trim().split(/[\r\n]/).pop();
  75. resolve(version);
  76. }
  77. });
  78. });
  79. }
  80. function formatLang() {
  81. const child = spawn(npmCmd, ['run', 'format-lang'], {shell: true});
  82. child.stdout.on('data', (chunk) => {
  83. console.log(chunk.toString());
  84. });
  85. return new Promise((resolve, reject) => {
  86. child.on('close', (code) => {
  87. if(code != 0) {
  88. reject(new Error('Failed to format lang'));
  89. } else {
  90. resolve();
  91. }
  92. });
  93. });
  94. }
  95. const onCompiled = async() => {
  96. console.log('Compiled successfully.');
  97. copyFiles(distPath, publicPath);
  98. clearOldFiles();
  99. const sshConfig = readSSHConfig();
  100. if(!sshConfig) {
  101. console.log('No SSH config, skipping upload');
  102. return;
  103. }
  104. const archiveName = 'archive.zip';
  105. const archivePath = path.join(__dirname, archiveName);
  106. execSync(`zip -r ${archivePath} *`, {
  107. cwd: publicPath
  108. });
  109. const ssh = new NodeSSH();
  110. await ssh.connect({
  111. ...sshConfig,
  112. tryKeyboard: true
  113. });
  114. console.log('SSH connected');
  115. await ssh.execCommand(`rm -rf ${sshConfig.publicPath}/*`);
  116. console.log('Cleared old files');
  117. await ssh.putFile(archivePath, path.join(sshConfig.publicPath, archiveName));
  118. console.log('Uploaded archive');
  119. await ssh.execCommand(`cd ${sshConfig.publicPath} && unzip ${archiveName} && rm ${archiveName}`);
  120. console.log('Unzipped archive');
  121. fs.unlinkSync(archivePath);
  122. ssh.connection?.destroy();
  123. };
  124. function compressFolder(folderPath) {
  125. const archive = {};
  126. function processFolder(folderPath, parentKey) {
  127. const folderName = path.basename(folderPath);
  128. const folderKey = parentKey ? `${parentKey}/${folderName}` : folderName;
  129. archive[folderKey] = {};
  130. const files = fs.readdirSync(folderPath);
  131. for(const file of files) {
  132. const filePath = path.join(folderPath, file);
  133. const stats = fs.statSync(filePath);
  134. if(stats.isFile()) {
  135. const fileContent = fs.readFileSync(filePath);
  136. const compressedContent = zlib.deflateSync(fileContent);
  137. archive[folderKey][file] = compressedContent;
  138. break;
  139. }/* else if(stats.isDirectory()) {
  140. processFolder(filePath, folderKey);
  141. } */
  142. }
  143. }
  144. processFolder(folderPath);
  145. const compressedArchive = zlib.gzipSync(JSON.stringify(archive));
  146. return compressedArchive;
  147. }
  148. /* exec(`npm run change-version ${version}${changelog ? ' ' + changelog : ''}; npm run build`, (err, stdout, stderr) => {
  149. if(err) {
  150. return;
  151. }
  152. // the *entire* stdout and stderr (buffered)
  153. console.log(`stdout: ${stdout}`);
  154. console.log(`stderr: ${stderr}`);
  155. }); */
  156. formatLang()
  157. .then(applyNewLang)
  158. .then((version) => {
  159. console.log('Applied new lang', version);
  160. return changeVersion(version);
  161. }, () => {
  162. console.error('Failed to apply new lang');
  163. return changeVersion('same');
  164. }).then(() => {
  165. const child = spawn(npmCmd, ['run', 'build'], {shell: true});
  166. child.stdout.on('data', (chunk) => {
  167. console.log(chunk.toString());
  168. });
  169. let error = '';
  170. child.stderr.on('data', (chunk) => {
  171. error += chunk.toString();
  172. });
  173. child.on('close', (code) => {
  174. if(code != 0) {
  175. console.error(error, `build child process exited with code ${code}`);
  176. } else {
  177. onCompiled();
  178. }
  179. });
  180. });