Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
},
"type": "module",
"scripts": {
"start": "node src/fm/fm.js",
"cli:args": "node src/cli/args.js --some-arg value1 --other 1337 --arg2 42",
"cli:env": "npx cross-env SOME=any RSS_foo=bar RSS_bar=baz node src/cli/env.js",
"cp": "node src/cp/cp.js",
Expand Down
86 changes: 86 additions & 0 deletions src/fm/fm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import readline from 'readline';
import * as nwd from './modules/nwd.mjs';
import * as customOs from './modules/os.mjs';
import * as customFs from './modules/customFs.mjs';
import * as hash from './modules/hash.mjs'
import * as compress from './modules/compress.mjs'
import * as errors from './modules/errors.mjs'
import os from 'os';

let userName = 'noname';
const invalidInput = 'Invalid input';
const printCurrentDirectory = () => {
console.log(`You are currently in ${process.cwd()}`);
};

const start = async () => {
process.chdir(os.homedir());
const args = process.argv.slice(2);
if (args.length && args[0].startsWith('--username=')) {
userName = args[0].slice(args[0].indexOf('=') + 1);
}

console.log(`Welcome to the File Manager, ${userName}! ${os.EOL}`);
printCurrentDirectory();
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });

const nwdCommands = ['up', 'cd', 'ls'];
const fileCommands = ['cat', 'add', 'rn', 'cp', 'mv', 'rm'];
const compressCommands = ['compress', 'decompress'];
rl.on('line', async (input) => {
try {
input = input.trim();
if (!input) {
console.log(errors.invalidInput);
printCurrentDirectory();
return;
}

if (input === '.exit') {
rl.close();
return;
}

let inputArgs = input.split(' ');
let command = inputArgs[0];
if (nwdCommands.includes(inputArgs[0])) {
command = 'nwd';
} else if (fileCommands.includes(inputArgs[0])) {
command = 'file';
} else if (compressCommands.includes(inputArgs[0])) {
command = 'compress';
}

switch (command) {
case 'nwd':
nwd.handleNWDCommand(inputArgs);
break;
case 'os':
customOs.handleOSCommand(inputArgs);
break;
case 'file':
customFs.handleFileCommand(inputArgs);
break;
case 'hash':
hash.calculateHash(inputArgs);
break;
case 'compress':
compress.handleCompressCommand(inputArgs);
break;
default:
console.log(errors.invalidInput);
}

printCurrentDirectory();
} catch(error) {
console.log(errors.operationFailed);
printCurrentDirectory();
}
});

rl.on('close', () => {
console.log(`Thank you for using File Manager, ${userName}, goodbye!`);
});
};

await start();
33 changes: 33 additions & 0 deletions src/fm/modules/compress.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import fs from 'fs';
import zlib from 'zlib';
import * as errors from './errors.mjs'

const handleCompressCommand = (inputArgs) => {
if (inputArgs.length !== 3) {
console.log(errors.invalidInput);
}

if (!fs.existsSync(inputArgs[1])) {
console.log(errors.invalidInput);
return;
}

const readStream = fs.createReadStream(inputArgs[1]);
const writeStream = fs.createWriteStream(inputArgs[2]);

let brotli;
switch (inputArgs[0]) {
case 'compress':
brotli = zlib.createBrotliCompress();
break;
case 'decompress':
brotli = zlib.createBrotliDecompress();
break;
default:
console.log(errors.invalidInput);
}

readStream.pipe(brotli).pipe(writeStream);
}

export { handleCompressCommand }
75 changes: 75 additions & 0 deletions src/fm/modules/customFs.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import fs from 'fs';
import path from 'path';
import * as errors from './errors.mjs'

const copyFile = (filePath, destination) => {
if (!fs.existsSync(filePath) || !fs.existsSync(destination)) {
console.log(errors.operationFailed);
return;
}

const copiedFilePath = path.join(destination, path.basename(filePath));
fs.createReadStream(filePath).pipe(fs.createWriteStream(copiedFilePath));
}

const removeFile = (filePath) => {
fs.rm(filePath, error => {
if (error) {
console.log(errors.operationFailed);
}
});
}

const handleFileCommand = async (inputArgs) => {
switch (inputArgs[0]) {
case 'cat':
const pathToFile = inputArgs[1];
if (!fs.existsSync(pathToFile)) {
console.log(errors.operationFailed);
return;
}

const readableStream = fs.createReadStream(pathToFile, {encoding: 'UTF-8'});
const chunks = [];

readableStream.on('data', (chunk) => {
chunks.push(chunk);
});

readableStream.on('end', () => {
console.log(chunks.join('').toString());
});
break;
case 'add':
const filePath = inputArgs[1];
const writeStream = fs.createWriteStream(filePath, { flags: 'w' });
writeStream.on('error', () => console.log(errors.operationFailed));
writeStream.write('');
writeStream.end();
break;
case 'rn':
const sourcePath = inputArgs[1];
const newFileName = inputArgs[2];
const newFilePath = path.join(path.dirname(sourcePath), newFileName);
fs.rename(sourcePath, newFilePath, error => {
if (error) {
console.log(errors.operationFailed);
}
});
break;
case 'cp':
copyFile(inputArgs[1], inputArgs[2]);
break;
case 'mv':
copyFile(inputArgs[1], inputArgs[2]);
removeFile(inputArgs[1]);
break;
case 'rm':
removeFile(inputArgs[1]);
break;
default:
console.log(errors.invalidInput);
}
}

export { handleFileCommand }
4 changes: 4 additions & 0 deletions src/fm/modules/errors.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const invalidInput = 'Invalid input';
const operationFailed = 'Operation failed';

export { invalidInput, operationFailed }
20 changes: 20 additions & 0 deletions src/fm/modules/hash.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import crypto from 'crypto';
import fs from 'fs';
import * as errors from './errors.mjs'

const calculateHash = async (inputArgs) => {
const pathToFile = inputArgs[1];
const hash = crypto.createHash('sha256');
hash.setEncoding('hex');
const fileStream = fs.createReadStream(pathToFile);

fileStream.on('error', (_) => console.log(errors.operationFailed));
fileStream.on('end', () => {
hash.end();
console.log(hash.read());
});

return fileStream.pipe(hash);
};

export { calculateHash }
30 changes: 30 additions & 0 deletions src/fm/modules/nwd.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import fs from 'fs';
import * as errors from './errors.mjs'

const handleNWDCommand = (inputArgs) => {
switch (inputArgs[0]) {
case 'up':
process.chdir('..');
break;
case 'cd':
process.chdir(inputArgs[1]);
break;
case 'ls':
fs.readdir(process.cwd(), { withFileTypes: true }, (_, entries) => {
const directory = entries.filter(entry => entry.isDirectory()).sort((a, b) => a.name.localeCompare(b.name))
.map(entry => { return {
'Name': entry.name, 'Type': 'directory'
}});
const files = entries.filter(entry => entry.isFile()).sort((a, b) => a.name.localeCompare(b.name))
.map(entry => { return {
'Name': entry.name, 'Type': 'file'
}});
console.table(directory.concat(files), ['Name', 'Type']);
});
break;
default:
console.log(errors.invalidInput);
}
}

export { handleNWDCommand }
26 changes: 26 additions & 0 deletions src/fm/modules/os.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import os from 'os';
import * as errors from './errors.mjs'

const getCPUInformation = () => {
const cpuObj = os.cpus();
return `Amount of CPUs: ${cpuObj.length}${os.EOL}${os.cpus()
.map(cpu => `Model: ${cpu.model}; Speed: ${cpu.speed/1000} GHz${os.EOL}`).join('')}`;
}

const handleOSCommand = (inputArgs) => {
const availableArgs = {
'--EOL': os.EOL,
'--cpus': getCPUInformation(),
'--homedir': os.homedir(),
'--username': os.userName,
'--architecture': os.arch(),
}
if (!(inputArgs[1] in availableArgs)) {
console.log(errors.invalidInput);
return;
}

console.log(availableArgs[inputArgs[1]]);
}

export { handleOSCommand }