mirror of
https://github.com/HeyPuter/puter
synced 2024-11-14 22:06:00 +00:00
209 lines
5.6 KiB
JavaScript
209 lines
5.6 KiB
JavaScript
/*
|
|
* Copyright (C) 2024 Puter Technologies Inc.
|
|
*
|
|
* This file is part of Puter.
|
|
*
|
|
* Puter is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published
|
|
* by the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
const fs = require('fs');
|
|
const fsp = fs.promises;
|
|
const path_ = require('path');
|
|
|
|
const EXCLUDE_LISTS = {
|
|
NOT_SOURCE: [
|
|
/^\.git/,
|
|
/^volatile\//,
|
|
/^node_modules\//,
|
|
/\/node_modules$/,
|
|
/^node_modules$/,
|
|
/package-lock\.json/,
|
|
/^src\/dev-center\/js/,
|
|
/src\/backend\/src\/public\/assets/,
|
|
/^src\/gui\/src\/lib/,
|
|
/^eslint\.config\.js$/,
|
|
]
|
|
};
|
|
|
|
EXCLUDE_LISTS.NOT_AGPL = [
|
|
...EXCLUDE_LISTS.NOT_SOURCE,
|
|
/^src\/puter-js/,
|
|
];
|
|
|
|
const hl_readdir = async path => {
|
|
const names = await fs.promises.readdir(path);
|
|
const entries = [];
|
|
|
|
for ( const name of names ) {
|
|
// wet: copied from phoenix shell
|
|
const stat_path = path_.join(path, name);
|
|
const stat = await fs.promises.lstat(stat_path);
|
|
entries.push({
|
|
name,
|
|
is_dir: stat.isDirectory(),
|
|
is_symlink: stat.isSymbolicLink(),
|
|
symlink_path: stat.isSymbolicLink() ? await fs.promises.readlink(stat_path) : null,
|
|
size: stat.size,
|
|
modified: stat.mtimeMs / 1000,
|
|
created: stat.ctimeMs / 1000,
|
|
accessed: stat.atimeMs / 1000,
|
|
mode: stat.mode,
|
|
uid: stat.uid,
|
|
gid: stat.gid,
|
|
});
|
|
}
|
|
|
|
return entries;
|
|
};
|
|
|
|
const walk = async function* walk (options, root_path, components = []) {
|
|
const current_path = path_.join(root_path, ...components);
|
|
const entries = await hl_readdir(current_path);
|
|
outer:
|
|
for ( const entry of entries ) {
|
|
entry.dirpath = current_path;
|
|
entry.path = path_.join(current_path, entry.name);
|
|
|
|
// TODO: labelled break?
|
|
for ( const exclude_regex of (options.excludes ?? []) ) {
|
|
if ( exclude_regex.test(entry.path) ) {
|
|
continue outer;
|
|
}
|
|
}
|
|
|
|
if ( ! options.pre_order ) yield entry;
|
|
if ( entry.is_dir ) {
|
|
yield* walk(options, root_path, [...components, entry.name]);
|
|
}
|
|
if ( options.pre_order ) yield entry;
|
|
}
|
|
};
|
|
|
|
const modes = {
|
|
primary_source_files: {
|
|
excludes: [
|
|
]
|
|
},
|
|
};
|
|
|
|
const util = require('util');
|
|
const exec = util.promisify(require('child_process').exec);
|
|
|
|
async function git_blame(path) {
|
|
const abs_path = path_.resolve(path);
|
|
|
|
try {
|
|
const { stdout } = await exec(`git blame -f "${abs_path}"`, {
|
|
maxBuffer: 1024 * 1024
|
|
});
|
|
|
|
const blameLines = stdout.split('\n');
|
|
const parsedBlame = blameLines
|
|
.map(line => {
|
|
if (!line.trim()) return null;
|
|
|
|
// console.log(line);
|
|
const parts = line.split(/\s+/);
|
|
let [commitHash, path, author, timestamp, lineNumber, , ,] = parts;
|
|
author = author.slice(1);
|
|
|
|
const o = {
|
|
commitHash,
|
|
author,
|
|
timestamp,
|
|
lineNumber: parseInt(lineNumber, 10),
|
|
};
|
|
return o;
|
|
})
|
|
.filter(item => item !== null)
|
|
;
|
|
|
|
return parsedBlame;
|
|
} catch (error) {
|
|
console.log('AZXV')
|
|
throw new Error(`Error executing git blame: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
// Example usage
|
|
const blame = async (path) => {
|
|
try {
|
|
const result = await git_blame(path);
|
|
// console.log('result?', result)
|
|
return result;
|
|
} catch ( e ) {
|
|
console.log('SKIPPED: ' + e.message);
|
|
}
|
|
return [];
|
|
}
|
|
|
|
const walk_test = async () => {
|
|
// console.log(await hl_readdir('.'));
|
|
for await ( const value of walk({
|
|
excludes: EXCLUDE_LISTS.NOT_SOURCE,
|
|
}, '.') ) {
|
|
if ( ! value.is_dir ) continue;
|
|
console.log('value', value.path);
|
|
}
|
|
}
|
|
|
|
const authors = {};
|
|
|
|
const blame_test = async () => {
|
|
// const results = await blame('src/backend/src/services/HostDiskUsageService.js');
|
|
// const results = await blame('package.json');
|
|
console.log('results', results)
|
|
return;
|
|
for ( const result of results ) {
|
|
if ( ! authors[result.author] ) {
|
|
authors[result.author] = { lines: 0 };
|
|
}
|
|
authors[result.author].lines++;
|
|
}
|
|
|
|
console.log('AUTHORS', authors);
|
|
}
|
|
|
|
|
|
/*
|
|
Contribution count function to test file walking and
|
|
git blame parsing.
|
|
*/
|
|
const walk_and_blame = async () => {
|
|
// console.log(await hl_readdir('.'));
|
|
for await ( const value of walk({
|
|
excludes: EXCLUDE_LISTS.NOT_SOURCE,
|
|
}, '.') ) {
|
|
if ( value.is_dir ) continue;
|
|
console.log('value', value.path);
|
|
const results = await blame(value.path);
|
|
for ( const result of results ) {
|
|
if ( ! authors[result.author] ) {
|
|
authors[result.author] = { lines: 0 };
|
|
}
|
|
authors[result.author].lines++;
|
|
}
|
|
}
|
|
console.log('AUTHORS', authors);
|
|
}
|
|
|
|
if ( require.main === module ) {
|
|
const main = walk_and_blame;
|
|
main();
|
|
}
|
|
|
|
module.exports = {
|
|
walk,
|
|
EXCLUDE_LISTS,
|
|
};
|