mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2025-03-07 11:04:36 +01:00
TERMINAL: Added deleting entire directories using rm (#1378)
This commit is contained in:
@ -29,7 +29,7 @@ export const TerminalHelpText: string[] = [
|
||||
" mv [src] [dest] Move/rename a text or script file",
|
||||
" nano [files...] Text editor - Open up and edit one or more scripts or text files",
|
||||
" ps Display all scripts that are currently running",
|
||||
" rm [file] Delete a file from the server",
|
||||
" rm [OPTIONS]... [FILE]... Delete a file from the server",
|
||||
" run [script] [-t n] [--tail] Execute a program or script",
|
||||
" [--ram-override n] [args...]",
|
||||
" scan Prints all immediately-available network connections",
|
||||
@ -358,12 +358,21 @@ export const HelpTexts: Record<string, string[]> = {
|
||||
nano: TemplatedHelpTexts.scriptEditor("nano"),
|
||||
ps: ["Usage: ps", " ", "Prints all scripts that are running on the current server", " "],
|
||||
rm: [
|
||||
"Usage: rm [file name]",
|
||||
"Usage: rm [OPTION]... [FILE]...",
|
||||
" ",
|
||||
"Removes the specified file from the current server. This command doesn't work for message (.msg) files.",
|
||||
"Remove the FILE(s).",
|
||||
" ",
|
||||
"WARNING: This is permanent and cannot be undone",
|
||||
"-f, --force Force removal of multiple files.",
|
||||
"-r, -R, --recursive Remove directories and their contents recursively.",
|
||||
"--no-preserve-root Do not treat '/' specially.",
|
||||
" ",
|
||||
"By default, rm does not operate on directories. To remove entire directories, use the --recursive (-r or -R) option.",
|
||||
" ",
|
||||
"To remove a file whose name starts with a '-', for example '-foo.js', use one of these commands:",
|
||||
"rm -- -foo.js",
|
||||
"rm ./-foo.js",
|
||||
" ",
|
||||
"Note that if you use rm to remove a file, the contents of the file will be lost. This is irreversible.",
|
||||
],
|
||||
run: [
|
||||
"Usage: run [file name] [-t num_threads] [--tail] [--ram-override ram_in_GBs] [args...]",
|
||||
|
@ -1,10 +1,91 @@
|
||||
import { Terminal } from "../../Terminal";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { PromptEvent } from "../../ui/React/PromptManager";
|
||||
import { hasScriptExtension } from "../../Paths/ScriptFilePath";
|
||||
import { hasTextExtension } from "../../Paths/TextFilePath";
|
||||
import type { Directory } from "../../Paths/Directory";
|
||||
import type { IReturnStatus } from "../../types";
|
||||
import type { FilePath } from "../../Paths/FilePath";
|
||||
|
||||
export function rm(args: (string | number | boolean)[], server: BaseServer): void {
|
||||
if (args.length !== 1) return Terminal.error("Incorrect number of arguments. Usage: rm [program/script]");
|
||||
const delTarget = Terminal.getFilepath(args[0] + "");
|
||||
if (!delTarget) return Terminal.error(`Invalid filename: ${args[0]}`);
|
||||
const status = server.removeFile(delTarget);
|
||||
if (!status.res && status.msg) Terminal.error(status.msg);
|
||||
const errors = {
|
||||
arg: (reason: string) => `Incorrect usage of rm command. ${reason}. Usage: rm [OPTION]... [FILE]...`,
|
||||
dirsProvided: () => "Incorrect usage of rm command. To delete directories, use the -r flag",
|
||||
invalidDir: (name: string) => `Invalid directory: ${name}`,
|
||||
invalidFile: (name: string) => `Invalid file: ${name}`,
|
||||
deleteFailed: (name: string, reason?: string) => `Failed to delete "${name}". ${reason ?? "Uncaught error"}`,
|
||||
rootDeletion: () =>
|
||||
"You are trying to delete all files within the root directory. If this is intentional, use the --no-preserve-root flag",
|
||||
} as const;
|
||||
|
||||
if (args.length === 0) return Terminal.error(errors["arg"]("No arguments provided"));
|
||||
|
||||
const recursive = args.includes("-r") || args.includes("-R") || args.includes("--recursive") || args.includes("-rf");
|
||||
const force = args.includes("-f") || args.includes("--force") || args.includes("-rf");
|
||||
const ignoreSpecialRoot = args.includes("--no-preserve-root");
|
||||
|
||||
const isTargetString = (
|
||||
arg: string | number | boolean,
|
||||
index: number,
|
||||
array: (string | number | boolean)[],
|
||||
): arg is string =>
|
||||
typeof arg === "string" && (!arg.startsWith("-") || (index - 1 >= 0 && array[index - 1] === "--"));
|
||||
const targets = args.filter(isTargetString);
|
||||
|
||||
if (targets.length === 0) return Terminal.error(errors["arg"]("No targets provided"));
|
||||
if (!ignoreSpecialRoot && targets.includes("/")) return Terminal.error(errors["rootDeletion"]());
|
||||
|
||||
const directories: Directory[] = [];
|
||||
const files: FilePath[] = [];
|
||||
|
||||
for (const target of targets) {
|
||||
if (!hasTextExtension(target) && !hasScriptExtension(target)) {
|
||||
const dirPath = Terminal.getDirectory(target);
|
||||
if (dirPath === null) return Terminal.error(errors["invalidDir"](target));
|
||||
if (!recursive) return Terminal.error(errors["dirsProvided"]());
|
||||
directories.push(dirPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
const file = Terminal.getFilepath(target);
|
||||
if (file === null) return Terminal.error(errors["invalidFile"](target));
|
||||
|
||||
files.push(file);
|
||||
}
|
||||
|
||||
for (const dir of directories) {
|
||||
for (const file of server.scripts.keys()) {
|
||||
if (file.startsWith(dir)) files.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
const targetList = files.map((file) => "* " + file.toString()).join("\n");
|
||||
|
||||
const reports: { target: string; result: IReturnStatus }[] = [];
|
||||
|
||||
const deleteSelectedTargets = () => {
|
||||
for (const file of files) {
|
||||
reports.push({ target: file, result: server.removeFile(file) });
|
||||
}
|
||||
|
||||
for (const report of reports) {
|
||||
if (report.result.res) {
|
||||
Terminal.success(`Deleted: ${report.target}`);
|
||||
} else {
|
||||
Terminal.error(errors["deleteFailed"](report.target, report.result.msg));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (force || files.length === 1) {
|
||||
deleteSelectedTargets();
|
||||
} else {
|
||||
PromptEvent.emit({
|
||||
txt: "Are you sure you want to delete these files? This is irreversible.\n\nDeleting:\n" + targetList,
|
||||
resolve: (value: string | boolean) => {
|
||||
if (typeof value === "string") throw new Error("PromptEvent got a string, expected boolean");
|
||||
if (value) deleteSelectedTargets();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user