test.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  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 fs = require('fs');
  20. const fsp = fs.promises;
  21. const path_ = require('path');
  22. const EXCLUDE_LISTS = {
  23. NOT_SOURCE: [
  24. /^\.git/,
  25. /^volatile\//,
  26. /^node_modules\//,
  27. /\/node_modules$/,
  28. /^node_modules$/,
  29. /package-lock\.json/,
  30. /^src\/dev-center\/js/,
  31. /src\/backend\/src\/public\/assets/,
  32. /^src\/gui\/src\/lib/,
  33. /^eslint\.config\.js$/,
  34. ]
  35. };
  36. EXCLUDE_LISTS.NOT_AGPL = [
  37. ...EXCLUDE_LISTS.NOT_SOURCE,
  38. /^src\/puter-js/,
  39. ];
  40. const hl_readdir = async path => {
  41. const names = await fs.promises.readdir(path);
  42. const entries = [];
  43. for ( const name of names ) {
  44. // wet: copied from phoenix shell
  45. const stat_path = path_.join(path, name);
  46. const stat = await fs.promises.lstat(stat_path);
  47. entries.push({
  48. name,
  49. is_dir: stat.isDirectory(),
  50. is_symlink: stat.isSymbolicLink(),
  51. symlink_path: stat.isSymbolicLink() ? await fs.promises.readlink(stat_path) : null,
  52. size: stat.size,
  53. modified: stat.mtimeMs / 1000,
  54. created: stat.ctimeMs / 1000,
  55. accessed: stat.atimeMs / 1000,
  56. mode: stat.mode,
  57. uid: stat.uid,
  58. gid: stat.gid,
  59. });
  60. }
  61. return entries;
  62. };
  63. const walk = async function* walk (options, root_path, components = []) {
  64. const current_path = path_.join(root_path, ...components);
  65. const entries = await hl_readdir(current_path);
  66. outer:
  67. for ( const entry of entries ) {
  68. entry.dirpath = current_path;
  69. entry.path = path_.join(current_path, entry.name);
  70. // TODO: labelled break?
  71. for ( const exclude_regex of (options.excludes ?? []) ) {
  72. if ( exclude_regex.test(entry.path) ) {
  73. continue outer;
  74. }
  75. }
  76. if ( ! options.pre_order ) yield entry;
  77. if ( entry.is_dir ) {
  78. yield* walk(options, root_path, [...components, entry.name]);
  79. }
  80. if ( options.pre_order ) yield entry;
  81. }
  82. };
  83. const modes = {
  84. primary_source_files: {
  85. excludes: [
  86. ]
  87. },
  88. };
  89. const util = require('util');
  90. const exec = util.promisify(require('child_process').exec);
  91. async function git_blame(path) {
  92. const abs_path = path_.resolve(path);
  93. try {
  94. const { stdout } = await exec(`git blame -f "${abs_path}"`, {
  95. maxBuffer: 1024 * 1024
  96. });
  97. const blameLines = stdout.split('\n');
  98. const parsedBlame = blameLines
  99. .map(line => {
  100. if (!line.trim()) return null;
  101. // console.log(line);
  102. const parts = line.split(/\s+/);
  103. let [commitHash, path, author, timestamp, lineNumber, , ,] = parts;
  104. author = author.slice(1);
  105. const o = {
  106. commitHash,
  107. author,
  108. timestamp,
  109. lineNumber: parseInt(lineNumber, 10),
  110. };
  111. return o;
  112. })
  113. .filter(item => item !== null)
  114. ;
  115. return parsedBlame;
  116. } catch (error) {
  117. console.log('AZXV')
  118. throw new Error(`Error executing git blame: ${error.message}`);
  119. }
  120. }
  121. // Example usage
  122. const blame = async (path) => {
  123. try {
  124. const result = await git_blame(path);
  125. // console.log('result?', result)
  126. return result;
  127. } catch ( e ) {
  128. console.log('SKIPPED: ' + e.message);
  129. }
  130. return [];
  131. }
  132. const walk_test = async () => {
  133. // console.log(await hl_readdir('.'));
  134. for await ( const value of walk({
  135. excludes: EXCLUDE_LISTS.NOT_SOURCE,
  136. }, '.') ) {
  137. if ( ! value.is_dir ) continue;
  138. console.log('value', value.path);
  139. }
  140. }
  141. const authors = {};
  142. const blame_test = async () => {
  143. // const results = await blame('src/backend/src/services/HostDiskUsageService.js');
  144. // const results = await blame('package.json');
  145. console.log('results', results)
  146. return;
  147. for ( const result of results ) {
  148. if ( ! authors[result.author] ) {
  149. authors[result.author] = { lines: 0 };
  150. }
  151. authors[result.author].lines++;
  152. }
  153. console.log('AUTHORS', authors);
  154. }
  155. /*
  156. Contribution count function to test file walking and
  157. git blame parsing.
  158. */
  159. const walk_and_blame = async () => {
  160. // console.log(await hl_readdir('.'));
  161. for await ( const value of walk({
  162. excludes: EXCLUDE_LISTS.NOT_SOURCE,
  163. }, '.') ) {
  164. if ( value.is_dir ) continue;
  165. console.log('value', value.path);
  166. const results = await blame(value.path);
  167. for ( const result of results ) {
  168. if ( ! authors[result.author] ) {
  169. authors[result.author] = { lines: 0 };
  170. }
  171. authors[result.author].lines++;
  172. }
  173. }
  174. console.log('AUTHORS', authors);
  175. }
  176. if ( require.main === module ) {
  177. const main = walk_and_blame;
  178. main();
  179. }
  180. module.exports = {
  181. walk,
  182. EXCLUDE_LISTS,
  183. };