<repo_name>ULL-ESIT-INF-DSI-2021/ull-esit-inf-dsi-20-21-prct09-async-fs-process-alu0101216126<file_sep>/README.md
# Desarrollo de Sistemas Informáticos - Grado en Ingeniería Informática - ULL
## Práctica 9 - Sistema de ficheros y creación de procesos en Node.js


Para ver el informe, haga clic [aquí](https://ull-esit-inf-dsi-2021.github.io/ull-esit-inf-dsi-20-21-prct09-async-fs-process-alu0101216126/)

En esta práctica se plantean una serie de ejercicios o retos a resolver haciendo uso de las APIs proporcionadas por Node.js para interactuar con el sistema de ficheros, así como para crear procesos.
<file_sep>/src/ejercicio-2.ts
import {spawn} from 'child_process';
import * as yargs from 'yargs';
import * as fs from 'fs';

/**
 * Provide information about the number of lines, words or characters that a text file contains. Making use of pipe, spawn and stream
 * @param path File path
 * @param characters Indicate if the user wants to see the characters amount
 * @param words Indicate if the user wants to see the words amount
 * @param lines Indicate if the user wants to see the lines amount
 */
function withPipe(path: string, characters: boolean, words: boolean, lines: boolean) {
  fs.access(path, fs.constants.F_OK, (err) => {
    if (err) console.log('Path doesn\'t exist');
    else {
      let wcOutput = '';
      const wc = spawn('wc', [path]);
      wc.stdout.on('data', (piece) => (wcOutput += piece));

      wc.on('close', () => {
        const wcOutputAsArray = wcOutput.split(/\s+/);
        if (lines) { // if the user wants to see the lines amount
          const echo = spawn('echo', [`File's lines: ${wcOutputAsArray[1]}`]);
          echo.stdout.pipe(process.stdout);
        }
        if (words) { // if the user wants to see the words amount
          const echo = spawn('echo', [`File's words: ${wcOutputAsArray[2]}`]);
          echo.stdout.pipe(process.stdout);
        }
        if (characters) { // if the user wants to see the characters amount
          const echo = spawn('echo', [`File's characters: ${wcOutputAsArray[3]}`]);
          echo.stdout.pipe(process.stdout);
        }
      });
    }
  });
}

/**
 * Provide information about the number of lines, words or characters that a text file contains. Without making use of pipe, spawn and stream
 * @param path File path
 * @param characters Indicate if the user wants to see the characters amount
 * @param words Indicate if the user wants to see the words amount
 * @param lines Indicate if the user wants to see the lines amount
 */
function withoutPipe(path: string, characters: boolean, words: boolean, lines: boolean): void {
  fs.access(path, fs.constants.F_OK, (err) => {
    if (err) console.log('Path doesn\'t exist');
    else {
      let wcOutput = '';
      const wc = spawn('wc', [path]);
      wc.stdout.on('data', (piece) => (wcOutput += piece));

      wc.on('close', () => {
        const wcOutputAsArray = wcOutput.split(/\s+/);
        let final = '';
        if (lines) { // if the user wants to see the lines amount
          final+= `File's lines: ${wcOutputAsArray[1]}\n`;
        }
        if (words) { // if the user wants to see the words amount
          final+= `File's words: ${wcOutputAsArray[2]}\n`;
        }
        if (characters) { // if the user wants to see the characters amount
          final+= `File's characters: ${wcOutputAsArray[3]}\n`;
        }
        console.log(final);
      });
    }
  });
}

/**
 * Yargs execution of the show command. The corresponding command line options must be included
 */
yargs.command({
  command: 'show',
  describe: 'Shows the information of a file',
  builder: {
    file: {
      describe: 'File\'s path',
      demandOption: true,
      type: 'string',
    },
    pipe: {
      describe: 'Whether to use a pipe or not',
      demandOption: true,
      type: 'boolean',
    },
    lines: {
      describe: 'Count lines or not',
      demandOption: true,
      type: 'boolean',
    },
    words: {
      describe: 'Count words or not',
      demandOption: true,
      type: 'boolean',
    },
    characters: {
      describe: 'Count characters or not',
      demandOption: true,
      type: 'boolean',
    },
  },
  handler(argv) {
    if (typeof argv.file === 'string' && typeof argv.pipe === 'boolean'&&
    typeof argv.characters === 'boolean' && typeof argv.words === 'boolean'&&
    typeof argv.lines === 'boolean') {
      if (argv.pipe) {
        withPipe(argv.file, argv.characters, argv.words, argv.lines);
      } else {
        withoutPipe(argv.file, argv.characters, argv.words, argv.lines);
      }
    }
  },
});

/**
 * Process arguments passed from command line to application.
 */
yargs.parse();
<file_sep>/src/ejercicio-4.ts
/* eslint-disable no-unused-vars */
/* eslint-disable brace-style */
import * as fs from 'fs';
import * as yargs from 'yargs';
import {spawn} from 'child_process';

/**
 * Yargs execution of the type command. The corresponding command line options must be included
 */
yargs.command({
  command: 'type',
  describe: 'Check if the received path is a directory or a file',
  builder: {
    path: {
      describe: 'path of the file or directory',
      demandOption: true,
      type: 'string',
    },
  },
  handler(argv) {
    if (typeof argv.path === 'string') {
      fs.stat(argv.path, (err, stats) => {
        if (!err) {
          if (stats.isFile()) console.log(argv.path + ' is a file');
          else if (stats.isDirectory()) console.log(argv.path + ' is a directroy');
        }
        else console.log(argv.path + '\'s path doesn\'t exist');
      });
    }
  },
});

/**
 * Yargs execution of the mkdir command. The corresponding command line options must be included
 */
yargs.command({
  command: 'mkdir',
  describe: 'Add an directory',
  builder: {
    path: {
      describe: 'Directory\'s path',
      demandOption: true,
      type: 'string',
    },
  },
  handler(argv) {
    if (typeof argv.path === 'string') {
      fs.mkdir(argv.path, {recursive: true}, (err) => {
        if (err) console.log('Cannot create directory in specified path');
        else console.log('Directory successfully created on: ' + argv.path);
      });
    }
  },
});

/**
 * Yargs execution of the list command. The corresponding command line options must be included
 */
yargs.command({
  command: 'list',
  describe: 'Shows the contents of a directory',
  builder: {
    path: {
      describe: 'Directory\'s path',
      demandOption: true,
      type: 'string',
    },
  },
  handler(argv) {
    if (typeof argv.path === 'string') {
      fs.readdir(argv.path, (err, directory) => {
        if (err) console.log(`Directory on ${argv.path} doesn´t exit`);

        else {
          console.log(`List of ${argv.path} elements:`);
          directory.forEach((file) => {console.log(file);});
        }
      });
    }
  },
});

/**
 * Yargs execution of the cat command. The corresponding command line options must be included
 */
yargs.command({
  command: 'cat',
  describe: 'Show the content of a file',
  builder: {
    path: {
      describe: 'File \'s path',
      demandOption: true,
      type: 'string',
    },
  },
  handler(argv) {
    if (typeof argv.path === 'string') {
      fs.readFile(argv.path, 'utf-8', (err, data) => {
        if (err) console.log(`Can´t read the file indicated`);
        else console.log(data);
      });
    }
  },
});

/**
 * Yargs execution of the rm command. The corresponding command line options must be included
 */
yargs.command({
  command: 'rm',
  describe: 'Delete a file or directory',
  builder: {
    path: {
      describe: 'path',
      demandOption: true,
      type: 'string',
    },
  },
  handler(argv) {
    if (typeof argv.path === 'string') {
      fs.lstat(argv.path, (err, stats) => {
        if (err) console.log(argv.path + '\'s path doesn\'t exist');

        else {
          if (stats.isFile()) {
            fs.rm(`${argv.path}`, (err) => {
              if (err) console.log(`Cannot delete the file`);
              else console.log(`Deleted file on path: ${argv.path}`);
            });
          } else {
            fs.rm(`${argv.path}`, {recursive: true}, (err) => {
              if (err) console.log(`Cannot delete the directory`);
              else console.log(`Deleted directory on path ${argv.path}`);
            });
          }
        }
      });
    }
  },
});

/**
 * Yargs execution of the cp command. The corresponding command line options must be included
 */
yargs.command({
  command: 'cp',
  describe: 'Copy a file or directory',
  builder: {
    oldPath: {
      describe: 'Old path',
      demandOption: true,
      type: 'string',
    },
    newPath: {
      describe: 'Newath',
      demandOption: true,
      type: 'string',
    },
  },
  handler(argv) {
    if (typeof argv.oldPath === 'string' && typeof argv.newPath === 'string' ) {
      let path: string = `${argv.newPath}`;
      const pos: number = path.lastIndexOf('/');
      path = path.substr(0, pos);
      fs.lstat(argv.oldPath, (err, stats) => {
        if (err) console.log(argv.oldPath + '\'s path doesn\'t exist');
        else {
          fs.lstat(path, (err, stats) => {
            if (err) console.log(argv.newPath + '\'s path doesn\'t exist');
            else {
              const cp = spawn('cp', ['-r', `${argv.oldPath}`, `${argv.newPath}`]);
              console.log('Elements copied');
            }
          });
        }
      });
    }
  },
});

/**
 * Process arguments passed from command line to application
 */
yargs.parse();
<file_sep>/src/ejercicio-3.ts
import * as fs from 'fs';
import * as yargs from 'yargs';

/**
 * Yargs execution of the watch command. The corresponding command line options must be included.
 */
yargs.command({
  command: 'watch',
  describe: 'Control user\'s changes',
  builder: {
    user: {
      describe: 'User to watch',
      demandOption: true,
      type: 'string',
    },
  },
  handler(argv) {
    if (typeof argv.user === 'string') {
      let prevSize: number = 0;
      let actualSize: number = 0;
      fs.readdir('./database/' + argv.user, (err, files) => {
        if (err) console.log('Path doesn\'t exist'); // error handling
        prevSize = files.length;
      });

      fs.access('./database/' + argv.user, fs.constants.F_OK, (err) => {
        let wait: boolean = false;

        // error handling
        if (err) console.log(argv.user + ' can\'t access');

        else {
          fs.watch('./database/' + argv.user, (eventType, filename) => {
            if (wait) return;
            wait = true;
            fs.readdir('./database/' + argv.user, (err, files) => {
              if (err) console.log('Unexpected error'); // error handling
              actualSize = files.length;

              if (prevSize < actualSize) console.log(`File ${filename} has been added\n`);
              else if (eventType === 'change') console.log(`File ${filename} has been modified\n`);
              else if (eventType === 'rename') console.log(`File ${filename} has been deleted\n`);

              prevSize = actualSize;
              setTimeout(() => {
                wait = false;
              }, 100);
            });
          });
        }
      });
    }
  },
});

/**
 * Process arguments passed from command line to application
 */
yargs.parse();
