LCOV - code coverage report
Current view: top level - lib - node-tee.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 279 279 100.0 %
Date: 2024-12-10 04:43:24 Functions: 7 8 87.5 %
Branches: 16 16 100.0 %

           Branch data     Line data    Source code
       1            [ + ]:         36 : /**
       2                 :         36 :  * tee (GNU coreutils) 8.32
       3                 :         36 :  * Copyright (C) 2020 Free Software Foundation, Inc.
       4                 :         36 :  * License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
       5                 :         36 :  * This is free software: you are free to change and redistribute it.
       6                 :         36 :  * There is NO WARRANTY, to the extent permitted by law.
       7                 :         36 :  *
       8                 :         36 :  * Written by Mike Parker, Richard M. Stallman, and David MacKenzie.
       9                 :         36 :  *
      10                 :         36 :  * Implemented in node.js by Essam A. El-Sherif.
      11                 :         36 :  *
      12                 :         36 :  * @module  node-tee
      13                 :         36 :  * @desc    A Node.js implementation of the {@link https://www.gnu.org/software/coreutils/ "GNU coreutils"} '{@link https://www.gnu.org/software/coreutils/manual/html_node/tee-invocation.html "tee"}' redirection command version 8.32.
      14                 :         36 :  * @version 1.0.1
      15                 :         36 :  * @author  Essam A. El-Sherif
      16                 :         36 :  */
      17                 :         36 : 
      18                 :         36 : /* Import nodeJS core modules */
      19                 :         36 : import process from 'node:process';
      20                 :         36 : import fs from 'node:fs';
      21                 :         36 : 
      22                 :         36 : /**
      23                 :         36 :  * @const errno {object} - Imported error symbols/messages
      24                 :         36 :  * @see   module:node-tee-errno.default
      25                 :         36 :  */
      26                 :         36 : import errno from './node-tee-errno.js';
      27                 :         36 : 
      28                 :         36 : /** @const {string} CMD_NODE - The coreutils node command */
      29                 :         36 : const CMD_NODE = 'node-tee';
      30                 :         36 : 
      31                 :         36 : /** @const {string} CMD_NODE_VER - The coreutils node command version */
      32                 :         36 : const CMD_NODE_VER = 'v1.0.1';
      33                 :         36 : 
      34                 :         36 : /** @const {object} cmdOptions - Command line arguments */
      35                 :         36 : const cmdOptions = {
      36                 :         36 :         readOpts:          true,            //    --
      37                 :         36 :         append:            false,           // -a --append
      38                 :         36 :         ignoreInterrupts:  false,           // -i --ignore-interrupts
      39                 :         36 :         outputError:      'warn-nopipe',    //    --output-error[=MODE]
      40                 :         36 : };
      41                 :         36 : 
      42                 :         36 : /** @const {Set} fileList - Files given as command line arguments */
      43                 :         36 : const fileList = new Set();
      44                 :         36 : 
      45                 :         36 : /**
      46                 :         36 :  *     function main
      47                 :         36 :  * function parseCmdLine()
      48                 :         36 :  * function processCmd()
      49                 :         36 :  * function getHelp()
      50                 :         36 :  * function getError(n)
      51                 :         36 :  *
      52                 :         36 :  * @func Main
      53                 :         36 :  * @desc The application entry point function
      54                 :         36 :  */
      55            [ + ]:         36 : (() => {
      56                 :         36 : 
      57                 :         36 :         parseCmdLine();
      58                 :         36 :         processCmd();
      59                 :         36 : 
      60                 :         36 : })('Main Function');
      61                 :         36 : 
      62                 :         36 : /**
      63                 :         36 :  * function main
      64                 :         36 :  *     function parseCmdLine()
      65                 :         36 :  * function processCmd()
      66                 :         36 :  * function getHelp()
      67                 :         36 :  * function getError(n)
      68                 :         36 :  *
      69                 :         36 :  * @func     parseCmdLine
      70                 :         36 :  * @desc     Command line parser function
      71                 :         36 :  * @requires module:node-tee-errno.default
      72                 :         36 :  */
      73            [ + ]:         36 : function parseCmdLine(){
      74                 :         36 : 
      75                 :         36 :         const args = process.argv;
      76                 :         36 : 
      77                 :         36 :         for(let i = 2; i < args.length; i++)
      78            [ + ]:         36 :                 if(cmdOptions.readOpts && args[i] === '--help'){
      79                 :         48 :                         process.stdout.write(`${getHelp()}\n`);
      80                 :         48 :                         process.exit(0);
      81                 :         48 :                 }
      82                 :         48 :                 else
      83                 :         48 :                 if(cmdOptions.readOpts && args[i] === '--version'){
      84                 :         48 :                         process.stdout.write(`${CMD_NODE_VER}\n`);
      85                 :         48 :                         process.exit(0);
      86                 :         48 :                 }
      87                 :         48 :                 else
      88                 :         48 :                 if(args[i] === '--')
      89                 :         48 :                         cmdOptions.readOpts = false;
      90                 :         48 :                 else
      91                 :         48 :                 if(cmdOptions.readOpts && args[i] === '--append')
      92                 :         48 :                         cmdOptions.append = true;
      93                 :         48 :                 else
      94                 :         48 :                 if(cmdOptions.readOpts && args[i] === '--ignore-interrupts')
      95                 :         48 :                         cmdOptions.ignoreInterrupts = true;
      96                 :         48 :                 else
      97            [ + ]:         48 :                 if(cmdOptions.readOpts && args[i].startsWith('--output-error=')){
      98                 :         12 :                         let str = args[i];
      99                 :         12 :                         str = str.replace('--output-error=', '');
     100                 :         12 : 
     101                 :         12 :                         switch(str){
     102                 :         12 :                                 case 'warn':
     103                 :         12 :                                 case 'warn-nopipe':
     104                 :         12 :                                 case 'exit':
     105                 :         12 :                                 case 'exit-nopipe':
     106                 :         12 :                                         cmdOptions.outputError = str;
     107                 :         12 :                                         break;
     108                 :         12 :                                 case '':
     109                 :         12 :                                         process.stderr.write(`${getError(0)}\n`);
     110                 :         12 :                                         process.exit(1);
     111                 :         12 :                                         break;
     112                 :         12 :                                 default:
     113                 :         12 :                                         process.stderr.write(`${getError(1).replace('_', str)}\n`);
     114                 :         12 :                                         process.exit(1);
     115                 :         12 :                                         break;
     116                 :         12 :                         }
     117            [ + ]:         12 :                 }
     118                 :         28 :                 else
     119                 :         28 :                 if(cmdOptions.readOpts && args[i] === '--output-error')
     120                 :         28 :                         true;
     121                 :         28 :                 else
     122                 :         28 :                 if(cmdOptions.readOpts && args[i].startsWith('--')){
     123                 :         28 :                         process.stderr.write(`${getError(2).replace('_', args[i])}\n`);
     124                 :         28 :                         process.exit(1);
     125                 :         28 :                 }
     126                 :         28 :                 else
     127                 :         28 :                 if(cmdOptions.readOpts && args[i] === '-')
     128                 :         28 :                         fileList.add(args[i]);
     129                 :         28 :                 else
     130            [ + ]:         28 :                 if(cmdOptions.readOpts && args[i].startsWith('-')){
     131                 :          1 :                         let str = args[i];
     132                 :          1 :                         str = str.replace('-', '');
     133                 :          1 : 
     134                 :          1 :                         for(let c of str){
     135                 :          1 :                                 switch(c){
     136                 :          1 :                                         case 'a':
     137                 :          1 :                                                 cmdOptions.append = true;
     138                 :          1 :                                                 break;
     139                 :          1 :                                         case 'i':
     140                 :          1 :                                                 cmdOptions.ignoreInterrupts = true;
     141                 :          1 :                                                 break;
     142                 :          1 :                                         case 'p':
     143                 :          1 :                                                 cmdOptions.outputError = 'warn-nopipe';
     144                 :          1 :                                                 break;
     145                 :          1 :                                         default:
     146                 :          1 :                                                 process.stderr.write(`${getError(3).replace('_', c)}\n`);
     147                 :          1 :                                                 process.exit(1);
     148                 :          1 :                                 }
     149                 :          1 :                         }
     150            [ + ]:          1 :                 }
     151                 :          1 :                 else
     152                 :          1 :                 if(args[i].startsWith('-') && !cmdOptions.readOpts)
     153                 :          1 :                         fileList.add(args[i]);
     154                 :          1 :                 else
     155                 :          1 :                         fileList.add(args[i]);
     156                 :         36 : }
     157                 :         36 : 
     158                 :         36 : /**
     159                 :         36 :  * function main
     160                 :         36 :  * function parseCmdLine()
     161                 :         36 :  *     function processCmd()
     162                 :         36 :  * function getHelp()
     163                 :         36 :  * function getError(n)
     164                 :         36 :  *
     165                 :         36 :  * @func processCmd
     166                 :         36 :  * @desc Command processer function
     167                 :         36 :  */
     168            [ + ]:         30 : function processCmd(){
     169                 :         30 : 
     170                 :         30 :         if(cmdOptions.ignoreInterrupts)
     171                 :         30 :                 process.on('SIGINT', () => {});
     172                 :         30 : 
     173            [ + ]:         30 :         process.stdout.on('error', (err) => {
     174                 :          8 :                 if(cmdOptions.outputError === 'warn' || cmdOptions.outputError === 'exit')
     175                 :          8 :                         process.stderr.write(`${CMD_NODE}: 'standard output': ${errno[err.code]}\n`);
     176                 :         30 :         });
     177                 :         30 : 
     178            [ + ]:         30 :         for(const file of fileList){
     179            [ + ]:         20 :                 fs.open(file, cmdOptions.append ? 'a' : 'w', (err, fd) => {
     180            [ + ]:         27 :                         if(err){
     181                 :         10 :                                 process.stderr.write(`${CMD_NODE}: ${file}: ${errno[err.code]}\n`);
     182                 :         10 : 
     183                 :         10 :                                 if(cmdOptions.outputError === 'exit' || cmdOptions.outputError === 'exit-nopipe')
     184                 :         10 :                                         process.exit(1);
     185                 :         10 :                                 else
     186                 :         10 :                                         process.exitCode = 1;
     187            [ + ]:         10 :                         }
     188                 :         10 :                         else{
     189                 :         10 :                                 const ws = fs.createWriteStream(file, {
     190                 :         10 :                                         flags: cmdOptions.append ? 'a' : 'w',
     191                 :         10 :                                         fd: fd
     192                 :         10 :                                 });
     193                 :         10 :                                 process.stdin.pipe(ws);
     194                 :         10 :                         }
     195                 :         20 :                 });
     196                 :         20 :         }
     197                 :         30 : 
     198                 :         30 :         process.stdin.pipe(process.stdout);
     199                 :         30 : }
     200                 :         36 : 
     201                 :         36 : /**
     202                 :         36 :  * function main
     203                 :         36 :  * function parseCmdLine()
     204                 :         36 :  * function processCmd()
     205                 :         36 :  *     function getHelp()
     206                 :         36 :  * function getError(n)
     207                 :         36 :  *
     208                 :         36 :  * @func   getHelp
     209                 :         36 :  * @return {string}
     210                 :         36 :  * @desc   Function to return help info
     211                 :         36 :  */
     212            [ + ]:          1 : function getHelp(){
     213                 :          1 : 
     214                 :          1 :         return `\
     215                 :          1 : Usage: ${CMD_NODE} [OPTION]... [FILE]...
     216                 :          1 : Copy standard input to each FILE, and also to standard output.
     217                 :          1 : 
     218                 :          1 :   -a, --append              append to the given FILEs, do not overwrite
     219                 :          1 :   -i, --ignore-interrupts   ignore interrupt signals
     220                 :          1 :   -p                        diagnose errors writing to non pipes
     221                 :          1 :       --output-error[=MODE]   set behavior on write error.  See MODE below
     222                 :          1 :       --help     display this help and exit
     223                 :          1 :       --version  output version information and exit
     224                 :          1 : 
     225                 :          1 : MODE determines behavior with write errors on the outputs:
     226                 :          1 :   'warn'         diagnose errors writing to any output
     227                 :          1 :   'warn-nopipe'  diagnose errors writing to any output not a pipe
     228                 :          1 :   'exit'         exit on error writing to any output
     229                 :          1 :   'exit-nopipe'  exit on error writing to any output not a pipe
     230                 :          1 : The default MODE for the -p option is 'warn-nopipe'.
     231                 :          1 : The default operation when --output-error is not specified, is to
     232                 :          1 : exit immediately on error writing to a pipe, and diagnose errors
     233                 :          1 : writing to non pipe outputs.`;
     234                 :          1 : }
     235                 :         36 : 
     236                 :         36 : /**
     237                 :         36 :  * function main
     238                 :         36 :  * function parseCmdLine()
     239                 :         36 :  * function processCmd()
     240                 :         36 :  * function getHelp()
     241                 :         36 :  *     function getError(n)
     242                 :         36 :  *
     243                 :         36 :  * @func   getError
     244                 :         36 :  * @param  {number} Error number
     245                 :         36 :  * @return {string} Error message
     246                 :         36 :  * @desc   Function to return error message
     247                 :         36 :  */
     248            [ + ]:          4 : function getError(n){
     249                 :          4 : 
     250                 :          4 : const error = [
     251                 :          4 : `\
     252                 :          4 : ${CMD_NODE}: ambiguous argument ‘’ for ‘--output-error’
     253                 :          4 : Valid arguments are:
     254                 :          4 :   - ‘warn’
     255                 :          4 :   - ‘warn-nopipe’
     256                 :          4 :   - ‘exit’
     257                 :          4 :   - ‘exit-nopipe’
     258                 :          4 : Try '${CMD_NODE} --help' for more information.`,
     259                 :          4 : 
     260                 :          4 : `\
     261                 :          4 : ${CMD_NODE}: invalid argument ‘_’ for ‘--output-error’
     262                 :          4 : Valid arguments are:
     263                 :          4 :   - ‘warn’
     264                 :          4 :   - ‘warn-nopipe’
     265                 :          4 :   - ‘exit’
     266                 :          4 :   - ‘exit-nopipe’
     267                 :          4 : Try '${CMD_NODE} --help' for more information.`,
     268                 :          4 : 
     269                 :          4 : `\
     270                 :          4 : ${CMD_NODE}: unrecognized option '_'
     271                 :          4 : Try '${CMD_NODE} --help' for more information.`,
     272                 :          4 : 
     273                 :          4 : `\
     274                 :          4 : ${CMD_NODE}: invalid option -- '_'
     275                 :          4 : Try '${CMD_NODE} --help' for more information.`,
     276                 :          4 : 
     277                 :          4 : ];
     278                 :          4 :         return error[n];
     279                 :          4 : }

Generated by: LCOV version 1.14