Fix CRLF and submodules with auto-generated copyright headers

We no longer add another character to the file every time it is committed, and instead now properly handle CRLF. Additionally submodules are no longer updated when they shouldn't be, without requiring a manual config edit.
This commit is contained in:
Michael Fabian 'Xaymar' Dirks
2024-07-05 15:19:18 +02:00
parent af243a8ce8
commit 22c7614e7c
14 changed files with 108 additions and 33 deletions
-1
View File
@@ -1,5 +1,4 @@
# AUTOGENERATED COPYRIGHT HEADER START # AUTOGENERATED COPYRIGHT HEADER START
# Copyright (C) NaN-NaN undefined
# Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com> # Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
# AUTOGENERATED COPYRIGHT HEADER END # AUTOGENERATED COPYRIGHT HEADER END
-1
View File
@@ -1,5 +1,4 @@
# AUTOGENERATED COPYRIGHT HEADER START # AUTOGENERATED COPYRIGHT HEADER START
# Copyright (C) NaN-NaN undefined
# Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com> # Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
# AUTOGENERATED COPYRIGHT HEADER END # AUTOGENERATED COPYRIGHT HEADER END
-1
View File
@@ -1,5 +1,4 @@
# AUTOGENERATED COPYRIGHT HEADER START # AUTOGENERATED COPYRIGHT HEADER START
# Copyright (C) NaN-NaN undefined
# Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com> # Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
# AUTOGENERATED COPYRIGHT HEADER END # AUTOGENERATED COPYRIGHT HEADER END
+3
View File
@@ -1,3 +1,6 @@
# AUTOGENERATED COPYRIGHT HEADER START
# Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
# AUTOGENERATED COPYRIGHT HEADER END
# Build Directories # Build Directories
/build /build
/build32 /build32
+3
View File
@@ -1,3 +1,6 @@
# AUTOGENERATED COPYRIGHT HEADER START
# Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
# AUTOGENERATED COPYRIGHT HEADER END
[submodule "cmake/cmake-version"] [submodule "cmake/cmake-version"]
path = cmake/cmake-version path = cmake/cmake-version
url = https://github.com/Xaymar/cmake-version.git url = https://github.com/Xaymar/cmake-version.git
+1 -1
View File
@@ -1,4 +1,4 @@
## AUTOGENERATED COPYRIGHT HEADER START # AUTOGENERATED COPYRIGHT HEADER START
# Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com> # Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
# AUTOGENERATED COPYRIGHT HEADER END # AUTOGENERATED COPYRIGHT HEADER END
cmake_minimum_required(VERSION 3.26...3.29.2 FATAL_ERROR) cmake_minimum_required(VERSION 3.26...3.29.2 FATAL_ERROR)
+1 -1
View File
@@ -1,4 +1,4 @@
## AUTOGENERATED COPYRIGHT HEADER START # AUTOGENERATED COPYRIGHT HEADER START
# Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com> # Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
# AUTOGENERATED COPYRIGHT HEADER END # AUTOGENERATED COPYRIGHT HEADER END
project(code_compiler project(code_compiler
-1
View File
@@ -1,5 +1,4 @@
# AUTOGENERATED COPYRIGHT HEADER START # AUTOGENERATED COPYRIGHT HEADER START
# Copyright (C) NaN-NaN undefined
# Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com> # Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
# AUTOGENERATED COPYRIGHT HEADER END # AUTOGENERATED COPYRIGHT HEADER END
/stranded2 /stranded2
+3
View File
@@ -1,3 +1,6 @@
; AUTOGENERATED COPYRIGHT HEADER START
; Copyright (C) 2017 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
; AUTOGENERATED COPYRIGHT HEADER END
; Ein simpler Lexer Test ; Ein simpler Lexer Test
Local Variable = 1.0 Local Variable = 1.0
Local Variable2$ = "Hallo Welt" Local Variable2$ = "Hallo Welt"
+3
View File
@@ -1,3 +1,6 @@
; AUTOGENERATED COPYRIGHT HEADER START
; Copyright (C) 2017 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
; AUTOGENERATED COPYRIGHT HEADER END
Graphics 800,600,32,2 Graphics 800,600,32,2
SetBuffer BackBuffer() SetBuffer BackBuffer()
+3
View File
@@ -1,3 +1,6 @@
; AUTOGENERATED COPYRIGHT HEADER START
; Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
; AUTOGENERATED COPYRIGHT HEADER END
Local iValue = 1, iValue2 = 1.2, iValue3 = "Hello World" Local iValue = 1, iValue2 = 1.2, iValue3 = "Hello World"
; iValue should be 1 ; iValue should be 1
; iValue2 should be 1, and print a warning ; iValue2 should be 1, and print a warning
+3
View File
@@ -1 +1,4 @@
; AUTOGENERATED COPYRIGHT HEADER START
; Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
; AUTOGENERATED COPYRIGHT HEADER END
Local iValue = 2 Local iValue = 2
+3
View File
@@ -1,3 +1,6 @@
; AUTOGENERATED COPYRIGHT HEADER START
; Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
; AUTOGENERATED COPYRIGHT HEADER END
Include "004-incl.bb" Include "004-incl.bb"
; Should be parsed as: ; Should be parsed as:
; Include(String("test.bb")) ; Include(String("test.bb"))
+84 -26
View File
@@ -1,8 +1,6 @@
// AUTOGENERATED COPYRIGHT HEADER START // AUTOGENERATED COPYRIGHT HEADER START
// Copyright (C) NaN-NaN undefined
// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com> // Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
// AUTOGENERATED COPYRIGHT HEADER END // AUTOGENERATED COPYRIGHT HEADER END
const ignoreList = [ const ignoreList = [
/^\.git$/gi, /^\.git$/gi,
/^cmake\/clang$/gi, /^cmake\/clang$/gi,
@@ -39,6 +37,10 @@ const formatStyleList = {
], exts: [ ], exts: [
".iss", ".iss",
".iss.in", ".iss.in",
".bb",
".b3d",
".b2d",
".bpl"
], ],
prepend: [ prepend: [
`; ${sectionStart}`, `; ${sectionStart}`,
@@ -111,6 +113,7 @@ const PATH = require("node:path");
const FS = require("node:fs"); const FS = require("node:fs");
const FSPROMISES = require("node:fs/promises"); const FSPROMISES = require("node:fs/promises");
const OS = require("os"); const OS = require("os");
const READLINE = require('node:readline');
if (!debug) if (!debug)
console.debug = function() {} console.debug = function() {}
@@ -191,11 +194,12 @@ class RateLimiter {
} }
let abortAllWork = false; let abortAllWork = false;
let gitRL = new RateLimiter(1); let gitRL = new RateLimiter(3);
let workRL = new RateLimiter(); let workRL = new RateLimiter();
let gitCurrentFiles; let gitCurrentFiles;
let gitUserName; let gitUserName;
let gitUserMail; let gitUserMail;
let gitSubmodules;
let gitDate = (new Date()).toISOString(); let gitDate = (new Date()).toISOString();
/** Run a process asynchronously, returning an array of messages. /** Run a process asynchronously, returning an array of messages.
@@ -265,6 +269,8 @@ async function runProcessAsync(path, args, options) {
async function git_isIgnored(path) { async function git_isIgnored(path) {
console.debug(arguments.callee.name, Array.from(arguments)); console.debug(arguments.callee.name, Array.from(arguments));
let rpath = PATH.relative(process.cwd(), path).replaceAll(PATH.sep, PATH.posix.sep); let rpath = PATH.relative(process.cwd(), path).replaceAll(PATH.sep, PATH.posix.sep);
// Check manual ignore list.
for (let ignore of ignoreList) { for (let ignore of ignoreList) {
if (ignore instanceof RegExp) { if (ignore instanceof RegExp) {
if (ignore.global) { if (ignore.global) {
@@ -282,6 +288,15 @@ async function git_isIgnored(path) {
} }
} }
// Check if this happens to be (in) a submodule.
let modules = await git_subModules()
for (let module of modules) {
if (rpath.startsWith(module)) {
return true;
}
}
// Finally check if git ignores this file.
let result = await gitRL.queue(runProcessAsync, "git", ["check-ignore", path], {}); let result = await gitRL.queue(runProcessAsync, "git", ["check-ignore", path], {});
return (result[0] == 0) return (result[0] == 0)
} }
@@ -299,6 +314,31 @@ async function git_getCurrentAuthor() {
return commitFormat.replace("%aI", gitDate).replace("%aN", gitUserName).replace("%aE", gitUserMail); return commitFormat.replace("%aI", gitDate).replace("%aN", gitUserName).replace("%aE", gitUserMail);
} }
async function git_subModules() {
if (!gitSubmodules) {
gitSubmodules = new Set();
let gitmodules = PATH.join(process.cwd(), ".gitmodules");
if ((await FSPROMISES.stat(gitmodules)).isFile()) {
let gmfs = FS.createReadStream(gitmodules);
const rl = READLINE.createInterface({
input: gmfs,
crlfDelay: Infinity
});
for await(const line of rl) {
let parts = line.trim().split("=");
if (parts.length > 1) {
if(parts[0].trim() == "path") {
gitSubmodules.add(parts[1].trim());
}
}
}
}
}
return gitSubmodules;
}
async function git_isInCurrentCommit(file) { async function git_isInCurrentCommit(file) {
console.debug(arguments.callee.name, Array.from(arguments)); console.debug(arguments.callee.name, Array.from(arguments));
if (!gitCurrentFiles) { if (!gitCurrentFiles) {
@@ -444,39 +484,46 @@ async function updateFile(file) {
} }
console.log(`Updating file '${file}'...`); console.log(`Updating file '${file}'...`);
// ToDo: Do we actually need to read the file first, or can we use the same rw stream?
// File contents. // File contents.
let content = await FSPROMISES.readFile(file); let contentBuf = await FSPROMISES.readFile(file);
let eol = (content.indexOf("\r\n") != -1 ? OS.EOL : "\n"); let eol = contentBuf.indexOf("\r\n") != -1 ? "\r\n" : "\n";
let insert = Buffer.from(header.join(eol) + eol); let headerBuf = Buffer.from(header.join(eol) + eol, "utf8");
// Find the starting point. // Find the starting point.
let startHeader = content.indexOf(sectionStart); let startHeader = contentBuf.indexOf(Buffer.from(header[0], "utf8"));
startHeader = content.lastIndexOf(eol, startHeader); if (startHeader != -1) {
startHeader += Buffer.from(eol).byteLength; //startHeader = contentBuf.lastIndexOf(eolBuf, startHeader);
//startHeader += eolb.byteLength;
}
console.log(sectionStart, startHeader);
// Find the ending point. // Find the ending point.
let endHeader = content.indexOf(sectionEnd); let endHeader = contentBuf.lastIndexOf(Buffer.from(header[header.length - 1], "utf8"));
endHeader = content.indexOf(eol, endHeader); if (endHeader != -1) {
endHeader += Buffer.from(eol).byteLength; endHeader += Buffer.from(header[header.length - 1], "utf8").byteLength;
endHeader += Buffer.byteLength(eol, "utf8");
}
console.log(sectionEnd, endHeader);
// Last check for early-exit here.
if (abortAllWork) { if (abortAllWork) {
return; return;
} }
let fd = await FSPROMISES.open(file, "w"); let fd = await FSPROMISES.open(file, "w");
let fp = []; if (startHeader == -1 || (endHeader < startHeader)) {
if ((startHeader >= 0) && (endHeader > startHeader)) { fd.write(headerBuf, 0, null, 0);
fd.write(contentBuf, 0, null, headerBuf.byteLength);
} else {
let pos = 0; let pos = 0;
if (startHeader > 0) { if (startHeader > 0) {
fd.write(content, 0, startHeader, 0); fd.write(contentBuf, 0, startHeader - Buffer.byteLength(eol, "utf8").byteLength, 0);
pos += startHeader; pos += startHeader;
} }
fd.write(insert, 0, undefined, pos); fd.write(headerBuf, 0, null, pos); pos += headerBuf.byteLength;
pos += insert.byteLength; fd.write(contentBuf, endHeader, null, pos);
fd.write(content, endHeader, undefined, pos);
} else {
fd.write(insert, 0, undefined, 0);
fd.write(content, 0, undefined, insert.byteLength);
} }
await fd.close(); await fd.close();
} catch (ex) { } catch (ex) {
@@ -490,11 +537,14 @@ async function updateFile(file) {
async function scanPath(path) { async function scanPath(path) {
console.debug(arguments.callee.name, Array.from(arguments)); console.debug(arguments.callee.name, Array.from(arguments));
// Abort here if the user aborted the process, or if the path is ignored. // Abort here if the user aborted the process, or if the path is ignored.
if (abortAllWork) { if (abortAllWork) {
return; return;
} }
console.log(`Scanning path '${path}'...`);
let promises = []; let promises = [];
await workRL.queue(async () => { await workRL.queue(async () => {
@@ -511,7 +561,6 @@ async function scanPath(path) {
} }
if (file.isDirectory()) { if (file.isDirectory()) {
console.log(`Scanning path '${fullname}'...`);
promises.push(scanPath(fullname)); promises.push(scanPath(fullname));
} else { } else {
promises.push(updateFile(fullname)); promises.push(updateFile(fullname));
@@ -535,6 +584,7 @@ async function scanPath(path) {
console.debug(root_path, PROCESS.argv, PROCESS.execArgv); console.debug(root_path, PROCESS.argv, PROCESS.execArgv);
var args = PROCESS.argv.slice(2); var args = PROCESS.argv.slice(2);
let promises = new Array();
while (args.length > 0) { while (args.length > 0) {
// Try to place ourselves where git actually is. // Try to place ourselves where git actually is.
while (!is_git_directory) { while (!is_git_directory) {
@@ -543,7 +593,7 @@ async function scanPath(path) {
} }
let entries = await FSPROMISES.readdir(PROCESS.cwd()); let entries = await FSPROMISES.readdir(PROCESS.cwd());
if (entries.includes(".git")) { if (entries.includes(".git") && ((await FSPROMISES.stat(PATH.join(PROCESS.cwd(), ".git"))).isDirectory())) {
console.log(`Found .git at '${process.cwd()}'.`); console.log(`Found .git at '${process.cwd()}'.`);
is_git_directory = true; is_git_directory = true;
} else { } else {
@@ -558,6 +608,12 @@ async function scanPath(path) {
return; return;
} }
if (abortAllWork) {
return;
}
git_getCurrentAuthor();
// Then proceed with normal work. // Then proceed with normal work.
let path = PATH.normalize(PATH.relative(process.cwd(), PATH.resolve(root_path, args[0]))); let path = PATH.normalize(PATH.relative(process.cwd(), PATH.resolve(root_path, args[0])));
@@ -567,15 +623,17 @@ async function scanPath(path) {
if (await git_isIgnored(path)) { if (await git_isIgnored(path)) {
console.log(`Ignoring path '${path}'...`); console.log(`Ignoring path '${path}'...`);
} else if(pathStat.isDirectory()) { } else if(pathStat.isDirectory()) {
console.log(`Scanning path '${path}'...`); //await scanPath(path);
await scanPath(path); promises.push(scanPath(path));
} else { } else {
await updateFile(path); //await updateFile(path);
promises.push(updateFile(path));
} }
} }
// Slice off the first argument and continue. // Slice off the first argument and continue.
args = args.slice(1); args = args.slice(1);
} }
await Promise.all(promises);
console.log("Done"); console.log("Done");
})(); })();