Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem while executing action of a command that is called inside action of another command? #1834

Closed
PreethiVuchuru27916 opened this issue Dec 21, 2022 · 4 comments

Comments

@PreethiVuchuru27916
Copy link

PreethiVuchuru27916 commented Dec 21, 2022

Action specified for the userCommand will get one more command from user using the readline function. That command is converted to a command array for parsing using the interpreter instance created. But the action for the net is not invoked when the readline reads a command from console . Below is the following code. I want the inner actions for the inner commands specified within a top level command to run .

const commander = require('commander')
const readline = require('readline');
const program = new commander.Command();
const interpreter = new commander.Command();

const userCommand = program.command('user');
userCommand
    .action(async() => {
            console.log("inside user")
            var rl = readline.createInterface({
                input: process.stdin,
                output: process.stdout
            });
           let waitForUserInput = async() => {
                  rl.question("command > ", async function(command) {
                  if (command == "quit"){
                      rl.close();
                  } else {
                      console.log("command entered is "+command)
                      var commandArr = command.split(" ");
                      const net = interpreter.command('net');
                      net 
                          .command('create')
                          .action(async() => {
                              console.log("create is success")
                          })
                      net 
                          .command('remove')
                          .action(async() => {
                              console.log("remove is success")
                          })
                      interpreter.parseAsync(commandArr);
                      await waitForUserInput()
                  }
            });
        }
await waitForUserInput();

     })
@shadowspawn
Copy link
Collaborator

shadowspawn commented Dec 21, 2022

Edit: this comment refers to an early version of the example code, which has been updated with much of this advice.

Your example code does not have a call to program.parse(), but that might have just got left out and be in the real code.

This is probably the main issue: you are calling waitForUserInput() inside the definition of waitForUserInput to process more commands, but you are not calling it in the action handler body to start the processing loop. The action handler just defines waitForUserInput but does not call it. Node stays running because readline.createInterface got called and the interface has not been closed.

A couple of other tips, but they don't break the example:

  1. To be safe you should create a fresh Command instance for each call to parse. So the definition of interpreter should be inside the loop and not global.
  2. You are using async code since readline.question returns a promise. You should probably await the answer, which means making the layers of function calls async, and once the action handler is async then call program.parseAsync() instead of program.parse().

@PreethiVuchuru27916
Copy link
Author

PreethiVuchuru27916 commented Dec 23, 2022

Hello,

Thanks for the response. I have tried the approach and I am not getting the action invoked still. So the action is not being invoked when I type net create when the user input is needed by the user command.

Below are the changes made.

const commander = require('commander')
const readline = require('readline');
const program = new commander.Command();
const userCommand = program.command('user');

userCommand
    .action(async() => {
            console.log("inside user")
            var rl = readline.createInterface({
                input: process.stdin,
                output: process.stdout
            });
           let waitForUserInput = async() => {
                  await rl.question("command > ", async function(command) {
                  if (command == "quit"){
                      rl.close();
                  } else {
                      console.log("command entered is "+command)
                      const interpreter = new commander.Command(command);
                      var commandArr = command.split(" ");
                      const net = interpreter.command('net');
                      net 
                          .command('create')
                          .action(async() => {
                              console.log("create is success")
                          })
                      net 
                          .command('remove')
                          .action(async() => {
                              console.log("remove is success")
                          })
                      interpreter.parseAsync(commandArr);
                      await waitForUserInput()
                  }
            });
        }
     await waitForUserInput()
     })
     program.parseAsync() 

This is the output.
[1] I am not having the action invoked for create.
[2] Program is ending after the parse is done. Is there a way my program can run continuously and accept commands from user and process accordingly?
image

@PreethiVuchuru27916
Copy link
Author

PreethiVuchuru27916 commented Dec 23, 2022

I just got lucky. I went through the documentation and found this interpreter.parse(commandArr, { from : 'user'}); Adding it got my problem solved and it works as expected. Thank you for your time.

const commander = require('commander')
const readline = require('readline');

const program = new commander.Command();
const interpreter = new commander.Command();

const userCommand = program.command('user');

userCommand
    .action(() => {
            console.log("inside user")
            var rl = readline.createInterface({
                input: process.stdin,
                output: process.stdout
            });
           let waitForUserInput = () => {
                rl.question("command > ", function(command) {
                  if (command == "quit"){
                      rl.close();
                  } else {
                      console.log("command entered is "+command)
                      var commandArr = command.split(" ");
                      const net = interpreter.command('net');
                      net 
                          .command('create')
                          .action(() => {
                              console.log("create is success")
                          })
                      net 
                          .command('remove')
                          .action(() => {
                              console.log("remove is success")
                          })
                      interpreter.parse(commandArr, { from : 'user'});
                    waitForUserInput()
                  }
            });
        }
     waitForUserInput()
     })
program.parse()

output:
image

@shadowspawn
Copy link
Collaborator

I missed the from, needed for the change in the inner loop to passing just the user arguments. Well spotted.

Thanks for the update, glad you got it working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants