@mieweb/wikigdrive
Version:
Google Drive to MarkDown synchronization
107 lines (106 loc) • 3.9 kB
JavaScript
import * as dntShim from "../../_dnt.shims.js";
import process from 'node:process';
const __filename = globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).filename;
export function sanitize(txt) {
txt = txt.replace(/[;"|]/g, '');
return txt;
}
export class GitExecuter {
constructor(gitScanner) {
Object.defineProperty(this, "gitScanner", {
enumerable: true,
configurable: true,
writable: true,
value: gitScanner
});
Object.defineProperty(this, "rootPath", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "logger", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.logger = gitScanner.logger;
this.rootPath = gitScanner.rootPath;
}
sshOptsEnv(sshParams) {
return {
GIT_SSH_COMMAND: sshParams?.privateKeyFile ? `ssh -i ${sanitize(sshParams.privateKeyFile)} -o StrictHostKeyChecking=no -o IdentitiesOnly=yes` : ''
};
}
committerEnv(committer) {
return {
GIT_AUTHOR_NAME: committer.name,
GIT_AUTHOR_EMAIL: committer.email,
GIT_COMMITTER_NAME: committer.name,
GIT_COMMITTER_EMAIL: committer.email,
};
}
async exec(cmd, opts = { env: {}, skipLogger: false, ignoreError: false }) {
if (!opts.skipLogger) {
this.logger.info(cmd, { stackOffset: 1, filename: __filename });
}
let [stdout, stderr] = ['', ''];
if (!opts.env) {
opts.env = {};
}
if (!opts.env['HOME']) {
opts.env['HOME'] = process.env.HOME;
}
if (!opts.env['PATH']) {
opts.env['PATH'] = process.env.PATH;
}
const command = new dntShim.Deno.Command('/bin/sh', {
args: ['-c', cmd],
cwd: this.rootPath,
env: opts.env,
stdout: 'piped',
stderr: 'piped',
});
const child = command.spawn();
const timer = setTimeout(() => {
this.logger.error('Process timeout', { filename: __filename });
child.kill();
}, 300_000);
const decoder = new TextDecoder();
const [status] = await Promise.all([
child.status,
child.stdout.pipeTo(new WritableStream({
write: (chunk, controller) => {
const text = decoder.decode(chunk);
stdout += text;
if (!opts.skipLogger) {
this.logger.info(text, { filename: __filename });
}
}
})),
child.stderr.pipeTo(new WritableStream({
write: (chunk, controller) => {
const text = decoder.decode(chunk);
stderr += text;
if (!opts.skipLogger) {
this.logger.error(text, { filename: __filename });
}
}
}))
]);
clearTimeout(timer);
if (!status.success && !opts.ignoreError) {
this.logger.error('Process exited with status: ' + status.code, { filename: __filename });
throw new Error('Process exited with status: ' + status.code + '\n' + stderr);
}
return { stdout, stderr };
}
async cmd(cmd, arg = '') {
if (!['status', 'remote -v', 'ls-files --stage', 'branch -m'].includes(cmd)) {
throw new Error('Forbidden command');
}
const result = await this.exec('git ' + cmd + ' ' + (arg || ''), { skipLogger: !this.gitScanner.debug });
return { stdout: result.stdout, stderr: result.stderr };
}
}