Skip to content

Commit 47f76cc

Browse files
committed
dev: add file walker
1 parent d3a9ba8 commit 47f76cc

File tree

3 files changed

+198
-1
lines changed

3 files changed

+198
-1
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
"check-translations": "node tools/check-translations.js"
3333
},
3434
"workspaces": [
35-
"src/*"
35+
"src/*",
36+
"tools/*"
3637
],
3738
"nodemonConfig": {
3839
"ext": "js, json, mjs, jsx, svg, css",

tools/file-walker/package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "file-walker",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "test.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"keywords": [],
10+
"author": "",
11+
"license": "AGPL-3.0-only",
12+
"dependencies": {
13+
}
14+
}
15+

tools/file-walker/test.js

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

0 commit comments

Comments
 (0)