test.js 5.5 KB

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