Skip to content
15 changes: 15 additions & 0 deletions common/colors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const COLORS = {
RED: '\x1b[31m',
GREEN: '\x1b[32m',
YELLOW: '\x1b[33m',
BLUE: '\x1b[34m',
MAGENTA: '\x1b[35m',
CYAN: '\x1b[36m',
WHITE: '\x1b[37m',
RESET: '\x1b[0m',
};

export default function logColoredMessage(message, color = 'white') {
const currentColor = COLORS[color.toUpperCase()] ?? COLORS.WHITE;
console.log(`${currentColor}${message}${COLORS.RESET}\n`)
};
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node src/index.js -- --username=your_username"
},
"repository": {
"type": "git",
Expand Down
148 changes: 147 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,147 @@
console.log(1)
import logColoredMessage from "../common/colors.js";
import os from "os";
import toUpperDirectory from "../utils/to-upper-directory.js";
import { changeDirectory } from "../utils/change-directory.js";
import list from "../utils/list.js";
import showFileContent from "../utils/showFileContent.js";
import createFile from "../utils/createFile.js";
import createFolder from "../utils/createFolder.js";
import renameFile from "../utils/renameFile.js";
import copyFile from "../utils/copyFile.js";
import removeFile from "../utils/removeFile.js";
import handleOSCommands from "../utils/handleOSCommands.js";
import calculateHash from "../utils/calculateHash.js";
import compressFile from "../utils/compressFile.js";
import decompressFile from "../utils/decompressFile.js";

const fileManager = async () => {
const argsArray = (process.argv).slice(2);
const userName = argsArray.find((arg) => arg.startsWith('--username'))?.split('=')[1] || 'guest';
const homeDir = os.homedir()
let currentDir = homeDir;
logColoredMessage(`Welcome to the File Manager, ${userName}!`, 'magenta');
logColoredMessage(`You are currently in ${currentDir}`, 'green');

process.stdin.on('data', async (chunk) => {
const input = chunk.toString().trim().split(' ');
const command = input[0];
const options = input.slice(1);

switch (command) {

case ('up'):
if (currentDir === homeDir) {
logColoredMessage(`\nAlready in home directory: ${currentDir}`, 'red');
} else {
currentDir = toUpperDirectory(currentDir);
}
break;
case ('cd'):
if (options[0]) {
currentDir = await changeDirectory(currentDir, options[0]);
} else {
logColoredMessage(`Invalid input`, 'red');
}
break;
case ('ls'):
await list(currentDir);
break;
case ('cat'):
if (options[0]) {
await showFileContent(currentDir, options[0]);
} else {
logColoredMessage(`Invalid input`, 'red');
}
break;
case ('add'):
if (options[0]) {
await createFile(currentDir, options[0]);
} else {
logColoredMessage(`Invalid input`, 'red');
}
break;
case ('mkdir'):
if (options[0]) {
await createFolder(currentDir, options[0]);
} else {
logColoredMessage(`Invalid input`, 'red');
}
break;
case ('rn'):
if (options[0] && options[1]) {
await renameFile(currentDir, options[0], options[1]);
} else {
logColoredMessage(`Invalid input`, 'red');
}
break;
case ('cp'):
if (options[0] && options[1]) {
await copyFile(currentDir, options[0], options[1]);
} else {
logColoredMessage(`Invalid input`, 'red');
}
break;
case ('mv'):
if (options[0] && options[1]) {
await copyFile(currentDir, options[0], options[1], { deleteSource: true });
} else {
logColoredMessage(`Invalid input`, 'red');
}
break;
case ('rm'):
if (options[0]) {
await removeFile(currentDir, options[0]);
} else {
logColoredMessage(`Invalid input`, 'red');
}
break;
case ('os'):
if (options[0] && options[0].startsWith('--')) {
handleOSCommands(options[0]);
} else {
logColoredMessage('Invalid input', 'red');
}
break;
case ('hash'):
if (options[0]) {
await calculateHash(currentDir, options[0]);
} else {
logColoredMessage('Invalid input', 'red');
}
break;
case ('compress'):
if (options[0] && options[1]) {
await compressFile(currentDir, options[0], options[1]);
} else {
logColoredMessage(`Invalid input`, 'red');
}

break;
case ('decompress'):
if (options[0] && options[1]) {
await decompressFile(currentDir, options[0], options[1]);
} else {
logColoredMessage(`Invalid input`, 'red');
}
break;
case ('.exit'):
process.exit();
default:
logColoredMessage(`Invalid input`, 'red');
}
logColoredMessage(`\nYou are currently in ${currentDir}`, 'green');
})



process.on('SIGINT', () => {
process.exit();
});

process.on('exit', () => {
logColoredMessage(`Thank you for using File Manager, ${userName}, goodbye!`, 'magenta');
});

};

await fileManager();
41 changes: 41 additions & 0 deletions utils/calculateHash.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

import path from 'path';
import crypto from 'crypto';
import fs from 'fs';
import { isFile } from './is-file.js';
import logColoredMessage from "../common/colors.js";


export default async function calculateHash(currentDirectory, pathToFile) {
try {

const normalizedFilePath = path.normalize(pathToFile);
let resolvedPathToFile = path.resolve(currentDirectory, normalizedFilePath);
if (await isFile(normalizedFilePath)) {
resolvedPathToFile = normalizedFilePath;
}

const readStream = fs.createReadStream(resolvedPathToFile);
const hash = crypto.createHash('sha256');
const hashPromise = new Promise((resolve, reject) => {
readStream.on('data', (chunk) => {
hash.update(chunk);
});
readStream.on('end', () => {
resolve(hash.digest('hex'));
});
readStream.on('error', (error) => {
reject(error);
});

});

const fileHash = await hashPromise;

logColoredMessage(`File hash is: ${fileHash}`, 'yellow');
} catch {
logColoredMessage('Invalid input', 'red');
}

}

26 changes: 26 additions & 0 deletions utils/change-directory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import path from 'path';
import logColoredMessage from "../common/colors.js";
import { isDirectory } from './is-directory.js';

export async function changeDirectory(currentDirectory, destinationDirectory) {
const relativePath = path.join(currentDirectory, destinationDirectory);

try {
const isRelativePath = await isDirectory(relativePath);
const isAbsolutePath = await isDirectory(destinationDirectory);

if (isRelativePath) {
return relativePath;
}

if (isAbsolutePath) {
return destinationDirectory;
} else {
throw new Error("Path doesn't exist");
}
} catch (err) {
logColoredMessage(err, 'red');
logColoredMessage('Operation failed', 'red');
return currentDirectory;
}
}
59 changes: 59 additions & 0 deletions utils/compressFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import fs from 'fs';
import zlib from 'zlib';
import path from 'path';
import logColoredMessage from "../common/colors.js";
import { isDirectory } from './is-directory.js';
import { isFile } from './is-file.js';


export default async function compressFile(currentDirectory, inputFilePath, destinationPath) {
try {
let resolvedPathToFile = path.resolve(currentDirectory, inputFilePath);
if (await isFile(inputFilePath)) {
resolvedPathToFile = inputFilePath;
}

let resolvedDestinationPath = path.resolve(currentDirectory, destinationPath);
if (await isDirectory(destinationPath)) {
resolvedDestinationPath = destinationPath;
}

const resolvedDestinationFile = path.resolve(resolvedDestinationPath, path.basename(resolvedPathToFile) + '.br');

if (await isFile(resolvedDestinationFile)) {
logColoredMessage('Invalid input', 'red');
return;
}

if (!(await isFile(resolvedPathToFile))) {
logColoredMessage('Invalid input', 'red');
return;
}

const readStream = fs.createReadStream(resolvedPathToFile);
const writeStream = fs.createWriteStream(resolvedDestinationFile);

const brotliStream = zlib.createBrotliCompress();

readStream.pipe(brotliStream).pipe(writeStream);

const fileCompressed = new Promise((resolve, reject) => {

writeStream.on('finish', () => {
resolve();
});

writeStream.on('error', (error) => {
reject(error);
}
);
}
);

await fileCompressed;
logColoredMessage(`File ${resolvedPathToFile} compressed to ${resolvedDestinationFile}`, 'yellow');

} catch (error) {
logColoredMessage('Invalid input', 'red');
}
}
51 changes: 51 additions & 0 deletions utils/copyFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@

import path from 'path';
import logColoredMessage from "../common/colors.js";
import fs from 'fs';
import { isFile } from './is-file.js';
import { isDirectory } from './is-directory.js';


export default async function copyFile(currentDirectory, pathToFile, destinationDirectory, options = { deleteSource: false }) {
try {
const normalizedFilePath = path.normalize(pathToFile);
let resolvedPathToFile = path.resolve(currentDirectory, normalizedFilePath);
if (await isFile(normalizedFilePath)) {
resolvedPathToFile = normalizedFilePath;
}


const normalizedDirectoryPath = path.normalize(destinationDirectory);
let resolvedPathToDirectory = path.resolve(currentDirectory, normalizedDirectoryPath);
if (await isDirectory(normalizedDirectoryPath)) {
resolvedPathToDirectory = normalizedDirectoryPath;
}
const parsedFilePath = path.parse(resolvedPathToFile);
const destinationFilePath = path.resolve(resolvedPathToDirectory, parsedFilePath.base);

const isOriginalFileExist = await isFile(resolvedPathToFile);
const isDirectoryExist = await isDirectory(resolvedPathToDirectory);
const isDestinationFileExist = await isFile(destinationFilePath);
if (!isOriginalFileExist || !isDirectoryExist || isDestinationFileExist) {
logColoredMessage(`Invalid input`, 'red');
return;
}

const readStream = fs.createReadStream(resolvedPathToFile);
const writeStream = fs.createWriteStream(destinationFilePath);
readStream.pipe(writeStream);
const copyPromise = new Promise((resolve, reject) => {
readStream.on('end', () => {
resolve();
})
});

await copyPromise;
if (options.deleteSource) {
fs.promises.unlink(resolvedPathToFile);
}
logColoredMessage(`File ${resolvedPathToFile} copied to ${resolvedPathToDirectory}`, 'yellow');
} catch (err) {
logColoredMessage(`Invalid input`, 'red');
}
}
15 changes: 15 additions & 0 deletions utils/createFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import path from 'path';
import fs from 'fs';
import logColoredMessage from "../common/colors.js";


export default async function createFile(currentPath, fileName) {
const filePath = path.resolve(currentPath, fileName);

try {
await fs.promises.writeFile(filePath, '', { flag: 'wx' });
logColoredMessage(`File ${fileName} created`, 'yellow');
} catch (err) {
logColoredMessage(`Invalid input`, 'red');
}
}
15 changes: 15 additions & 0 deletions utils/createFolder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import path from 'path';
import fs from 'fs';
import logColoredMessage from "../common/colors.js";


export default async function createFolder(currentPath, folderName) {
const folderPath = path.resolve(currentPath, folderName);

try {
await fs.promises.mkdir(folderPath);
logColoredMessage(`Folder ${folderPath} created`, 'yellow');
} catch (err) {
logColoredMessage(`Invalid input`, 'red');
}
}
Loading