securityos/components/apps/Terminal/processGit.ts

115 lines
3.2 KiB
TypeScript

import type { FSModule } from "browserfs/dist/node/core/FS";
import { help } from "components/apps/Terminal/functions";
import type { LocalEcho } from "components/apps/Terminal/types";
import type index from "isomorphic-git";
import type {
AuthCallback,
GitAuth,
MessageCallback,
ProgressCallback,
} from "isomorphic-git";
import type { ParsedArgs } from "minimist";
import { join } from "path";
const corsProxy = "https://cors.isomorphic-git.org";
const UPDATE_FOLDER_COMMANDS = new Set([
"checkout",
"clone",
"fetch",
"init",
"merge",
"pull",
]);
export const commands: Record<string, string> = {
add: "Add a file to the git index (aka staging area)",
branch: "Create a branch",
checkout: "Checkout a branch",
clone: "Clone a repository",
commit: "Create a new commit",
fetch: "Fetch commits from a remote repository",
init: "Initialize a new repository",
log: "Get commit descriptions from the git history",
merge: "Merge two branches",
pull: "Fetch and merge commits from a remote repository",
push: "Push a branch or tag",
status: "Tell whether a file has been changed",
tag: "Create a lightweight tag",
version: "Return the version number of isomorphic-git",
};
type GitOptions = Record<string, unknown>;
type GitFunction = (options: GitOptions) => Promise<string | void>;
const processGit = async (
[command, ...args]: string[],
cd: string,
localEcho: LocalEcho,
fs: FSModule,
updateFolder: (folder: string, newFile?: string, oldFile?: string) => void
): Promise<void> => {
const git = await import("isomorphic-git");
if (command in git) {
const http = await import("isomorphic-git/http/web");
const { default: minimist } = await import("minimist");
const { username, password, ...cliArgs } = minimist(args) as GitAuth &
ParsedArgs;
const onAuth: AuthCallback = () => ({ password, username });
const onMessage: MessageCallback = (message = "") =>
localEcho.println(`remote: ${message.trim()}`);
const events: string[] = [];
const onProgress: ProgressCallback = ({ phase }): void => {
if (events[events.length - 1] !== phase) {
localEcho.println(phase);
events.push(phase);
}
};
const options = {
...cliArgs,
corsProxy,
dir: cd,
fs,
http,
onAuth,
onMessage,
onProgress,
};
if (command === "clone") {
const dirName =
(cliArgs.url as string)
?.split("/")
.pop()
?.replace(/\.git$/, "") || "";
if (dirName) {
localEcho.println(`Cloning into '${dirName}'...`);
options.dir = join(cd, dirName);
}
}
try {
const result = await (
git[command as keyof typeof index] as GitFunction
)?.(options);
if (typeof result === "string") {
localEcho.println(result);
}
} catch (error) {
localEcho.println((error as Error).message);
}
if (UPDATE_FOLDER_COMMANDS.has(command)) {
updateFolder(cd);
}
} else {
help(localEcho, commands);
}
};
export default processGit;