* docs: prepare Vendoo 1.41.2 git-ignore boundary hotfix * fix: track native source modules with root-anchored runtime ignores
109 lines
4.1 KiB
JavaScript
109 lines
4.1 KiB
JavaScript
import {
|
|
chmodSync,
|
|
copyFileSync,
|
|
existsSync,
|
|
lstatSync,
|
|
mkdirSync,
|
|
readdirSync,
|
|
rmSync,
|
|
} from 'node:fs';
|
|
import { basename, dirname, extname, join, relative, resolve, sep } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const normalize = value => value.split(sep).join('/').replace(/^\.\//, '');
|
|
const allowedEnvTemplates = new Set(['.env.example', '.env.docker.example']);
|
|
const skippedTopLevelDirs = new Set([
|
|
'node_modules', 'runtime', 'docker-data', 'uploads', 'backups', 'logs',
|
|
'sessions', 'tmp', 'temp', '__pycache__', 'release-output', 'operations', 'updates', 'modules',
|
|
'archiv', 'archive', 'archives',
|
|
]);
|
|
const skippedLocalAiDirs = new Set(['local-ai/comfyui', 'local-ai/downloads', 'local-ai/extract-temp']);
|
|
const skippedExactFiles = new Set([
|
|
'.vendoo-install-mode', '.vendoo-github-state.json',
|
|
'pending-operation.json', 'last-operation.json', 'first-admin-code.txt',
|
|
]);
|
|
const skippedExtensions = new Set([
|
|
'.db', '.sqlite', '.sqlite3', '.log', '.key', '.pem', '.pfx', '.p12',
|
|
]);
|
|
|
|
export function shouldSkipStagingEntry(relativePath, stat) {
|
|
const rel = normalize(relativePath);
|
|
const parts = rel.split('/');
|
|
const name = basename(rel);
|
|
const lower = rel.toLowerCase();
|
|
|
|
if (!rel || rel === '.git' || lower.startsWith('.git/')) return true;
|
|
if (skippedTopLevelDirs.has(parts[0].toLowerCase())) return true;
|
|
if (parts.some(part => part.toLowerCase() === '__pycache__') || /\.pyc$/i.test(rel)) return true;
|
|
if ([...skippedLocalAiDirs].some(dir => lower === dir || lower.startsWith(`${dir}/`))) return true;
|
|
if (/^\.env(?:\..+)?$/i.test(name) && !allowedEnvTemplates.has(rel)) return true;
|
|
if (skippedExactFiles.has(name.toLowerCase())) return true;
|
|
if (/\.(?:db|sqlite|sqlite3)-(?:wal|shm)$/i.test(name)) return true;
|
|
if (skippedExtensions.has(extname(name).toLowerCase())) return true;
|
|
if (stat.isSymbolicLink()) return true;
|
|
return false;
|
|
}
|
|
|
|
function cleanDestination(destination) {
|
|
if (!existsSync(join(destination, '.git'))) {
|
|
throw new Error(`Ziel ist kein geklontes Git-Repository: ${destination}`);
|
|
}
|
|
for (const name of readdirSync(destination)) {
|
|
if (name === '.git') continue;
|
|
rmSync(join(destination, name), { recursive: true, force: true });
|
|
}
|
|
}
|
|
|
|
export function prepareGitStaging(sourceRoot, destinationRoot) {
|
|
const source = resolve(sourceRoot);
|
|
const destination = resolve(destinationRoot);
|
|
if (source === destination) throw new Error('Quell- und Zielordner dürfen nicht identisch sein.');
|
|
if (!existsSync(source)) throw new Error(`Quellordner fehlt: ${source}`);
|
|
if (!existsSync(destination)) throw new Error(`Zielordner fehlt: ${destination}`);
|
|
|
|
cleanDestination(destination);
|
|
let copied = 0;
|
|
let skipped = 0;
|
|
|
|
function walk(current) {
|
|
for (const name of readdirSync(current)) {
|
|
const absolute = join(current, name);
|
|
const rel = normalize(relative(source, absolute));
|
|
const stat = lstatSync(absolute);
|
|
if (shouldSkipStagingEntry(rel, stat)) {
|
|
skipped += 1;
|
|
continue;
|
|
}
|
|
const target = join(destination, rel);
|
|
if (stat.isDirectory()) {
|
|
mkdirSync(target, { recursive: true });
|
|
walk(absolute);
|
|
} else if (stat.isFile()) {
|
|
mkdirSync(dirname(target), { recursive: true });
|
|
copyFileSync(absolute, target);
|
|
try { chmodSync(target, stat.mode & 0o777); } catch {}
|
|
copied += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
walk(source);
|
|
return { source, destination, copied, skipped };
|
|
}
|
|
|
|
const invokedPath = process.argv[1] ? resolve(process.argv[1]) : '';
|
|
if (invokedPath === fileURLToPath(import.meta.url)) {
|
|
const [, , source, destination] = process.argv;
|
|
if (!source || !destination) {
|
|
console.error('Aufruf: node tools/prepare-git-staging.mjs <Quellordner> <geklontes Zielrepository>');
|
|
process.exit(64);
|
|
}
|
|
try {
|
|
const result = prepareGitStaging(source, destination);
|
|
console.log(`Git-Staging vorbereitet: ${result.copied} Quelldateien kopiert; ${result.skipped} lokale Einträge ausgeschlossen.`);
|
|
} catch (error) {
|
|
console.error(`[FEHLER] Git-Staging konnte nicht vorbereitet werden: ${error.message}`);
|
|
process.exit(1);
|
|
}
|
|
}
|