main.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. * Copyright (C) 2024-present Puter Technologies Inc.
  3. *
  4. * This file is part of Puter.
  5. *
  6. * Puter is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published
  8. * by the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. const path_ = require('node:path');
  20. const fs = require('node:fs');
  21. const { spawnSync } = require('node:child_process');
  22. const prompt = require('prompt-sync')({sigint: true});
  23. const ind_str = () => Array(ind).fill(' --').join('');
  24. let ind = 0;
  25. const log = {
  26. // log with unicode warning symbols in yellow
  27. warn: (msg) => {
  28. console.log(`\x1b[33;1m[!]${ind_str()} ${msg}\x1b[0m`);
  29. },
  30. crit: (msg) => {
  31. console.log(`\x1b[31;1m[!]${ind_str()} ${msg}\x1b[0m`);
  32. },
  33. info: (msg) => {
  34. console.log(`\x1B[36;1m[i]\x1B[0m${ind_str()} ${msg}`);
  35. },
  36. named: (name, value) => {
  37. console.log(`\x1B[36;1m[i]${ind_str()} ${name}\x1B[0m ${value}`);
  38. },
  39. error: e => {
  40. if ( e instanceof UserError ) {
  41. log.crit(e.message);
  42. } else {
  43. console.error(e);
  44. }
  45. },
  46. indent () { ind++; },
  47. dedent () { ind--; },
  48. heading (title) {
  49. const circle = '🔵';
  50. console.log(`\n\x1b[36;1m${circle} ${title} ${circle}\x1b[0m`);
  51. }
  52. };
  53. const areyousure = (message, options = {}) => {
  54. const { crit } = options;
  55. const logfn = crit ? log.crit : log.warn;
  56. logfn(message);
  57. const answer = prompt(`\x1B[35;1m[?]\x1B[0m ${ options?.prompt ?? 'Are you sure?' } (y/n): `);
  58. if ( answer !== 'y' ) {
  59. if ( options.fail_hint ) {
  60. log.info(options.fail_hint);
  61. }
  62. console.log(`\x1B[31;21;1mAborted.\x1B[0m`);
  63. process.exit(1);
  64. }
  65. }
  66. if ( ! fs.existsSync('.is_puter_repository') ) {
  67. throw new Error('This script must be run from the root of a puter repository');
  68. }
  69. areyousure(
  70. 'This script will delete all data in the database. Are you sure you want to proceed?',
  71. { crit: true }
  72. )
  73. let backup_created = false;
  74. const DBPATH = 'volatile/runtime/puter-database.sqlite';
  75. const delete_db = () => {
  76. if ( ! fs.existsSync(DBPATH) ) {
  77. log.info('No database file to remove');
  78. // no need to create a backup if the database doesn't exist
  79. backup_created = true;
  80. return;
  81. }
  82. if ( ! backup_created ) {
  83. log.info(`Creating a backup of the database...`);
  84. const RANDOM = Math.floor(Math.random() * 1000000);
  85. const DATE = new Date().toISOString().replace(/:/g, '-');
  86. fs.renameSync(DBPATH, `${DBPATH}_${DATE}_${RANDOM}.bak`);
  87. backup_created = true;
  88. return;
  89. }
  90. log.info('Removing database file');
  91. fs.unlinkSync(DBPATH);
  92. }
  93. const pwd = process.cwd();
  94. const boot_script_path = path_.join(pwd, 'tools/migrations-test/noop.puter.json');
  95. const launch_puter = (args) => {
  96. const ret = spawnSync(
  97. 'node',
  98. ['tools/run-selfhosted.js', ...args],
  99. {
  100. stdio: 'inherit',
  101. env: {
  102. ...process.env,
  103. NO_VAR_RUNTIME: '1',
  104. },
  105. }
  106. );
  107. ret.ok = ret.status === 0;
  108. return ret;
  109. };
  110. {
  111. delete_db();
  112. log.info(`Test case: fresh install`);
  113. if ( ! launch_puter([
  114. '--quit-on-alarm',
  115. `--boot-script=${boot_script_path}`,
  116. ]).ok ) {
  117. log.crit('Migration to v21 raised alarm');
  118. process.exit(1);
  119. }
  120. }
  121. {
  122. delete_db();
  123. log.info(`Test case: migrate to 21, then migrate to 24`);
  124. if ( ! launch_puter([
  125. `--database-target-version=21`,
  126. '--quit-on-alarm',
  127. `--boot-script=${boot_script_path}`,
  128. ]).ok ) {
  129. log.crit('Migration to v21 raised alarm');
  130. process.exit(1);
  131. }
  132. if ( ! launch_puter([
  133. `--database-target-version=24`,
  134. '--quit-on-alarm',
  135. `--boot-script=${boot_script_path}`,
  136. ]).ok ) {
  137. log.crit('Migration to v24 raised alarm');
  138. process.exit(1);
  139. }
  140. }
  141. log.info('No migration scripts produced any obvious errors.');
  142. log.warn('This is not a substitute for release candidate migration testing!');