Aws-cdk: --app command with no arguments

Created on 22 Mar 2020  路  5Comments  路  Source: aws/aws-cdk

CDK doesn't support executing a command with no arguments to run an app. Suppose that "foobar" is an executable in your $PATH. The following command doesn't work as expected:

$ cdk --app "foobar" ls

ENOENT: no such file or directory, stat 'foobar'

while the command below works:

$ cdk --app "foobar arg" ls

You can reproduce this behavior with any executable. For instance:

$ cdk --app "cp" ls

and

$ cdk --app "cp /path1 /path2" ls

On the other hand, if the executable doesn't exist for real, the error is:

/bin/sh: foobar: command not found
Subprocess exited with error 127

The same goes if the "no argument" app is specified in the cdk.json configuration file instead of the command line.

{
  "app": "foobar"
}
bug in-progress p1 packagtools

All 5 comments

I found the bug. The culprit is this fs.stat call. If a command without arguments is specified it tries to stat it. In turn that forces the user to specify the executable's full path or a command with at least 1 argument. The logic of guessExecutable function is wrong. The easy fix would be to simply ignore any fs.stat error and return the commandLine argument untouched. A more robust solution would involve using a package like lookpath to check if a command exists and where the executable file is.

@rix0rrr sorry for pinging directly but that one is an easy fix and it's blocking us from using CDK. Thanks

@philtay - investigating your suggestion re: using lookpath

@shivlaks thanks a lot for looking into this. Whatever mimics golang LookPath would do. Using the suggested package the guessExecutable function would look something like this:

async function guessExecutable(commandLine: string[]) {
  if (commandLine.length === 1) {
    const exec = await lookpath(commandLine[0]);

    if (!exec) {
      return commandLine;
    }

    const fstat = await fs.stat(exec);
    // tslint:disable-next-line:no-bitwise
    const isExecutable = (fstat.mode & fs.constants.X_OK) !== 0;
    const isWindows = process.platform === "win32";
    const handler = EXTENSION_MAP.get(path.extname(exec));

    if (handler && (!isExecutable || isWindows)) {
      return handler(exec);
    }
  }

  return commandLine;
}

@philtay we discussed using lookPath and elected to go with the simpler workaround and make it more robust following that instead of taking on a new dependency.

I'll try to get to it this week!

Thank you @shivlaks. That's a perfectly fine solution. If possible, please also add a unit test. These things are a little tricky and it's easy to introduce a regression.

Was this page helpful?
0 / 5 - 0 ratings