test.js 5.5 KB

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