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

Should argv include runtime parts (binary/script/runtime args)? #3

Open
CanadaHonk opened this issue Jan 22, 2024 · 8 comments
Open
Labels
agenda+ Should be discussed next meeting spec

Comments

@CanadaHonk
Copy link
Member

CanadaHonk commented Jan 22, 2024

argv is traditionally all arguments, which would include: runtime binary, script being ran, and runtime arguments ("runtime parts"). Should ours?

Existing examples:

  • process.argv (Node): includes runtime parts
  • Deno.args (Deno): does not include runtime parts (they can be got separately with Deno.execPath(), etc)
@CanadaHonk CanadaHonk changed the title Should argv include binary? Should argv include runtime parts (binary/script/runtime args)? Jan 22, 2024
@lucacasonato
Copy link
Member

I would argue against including "runtime args" (args interpreted by the runtime) in the args exposed to users. My reasoning is that arg parsers are not portable across runtimes otherwise, because invocation may happen in different ways across runtimes. For example, in Node you exec with node <filename> where as in Deno you use deno run <filename>. If the arg list exposes the raw [deno, run, <filename>] and [node, <filename>] libraries need to be aware that they need to start reading at the third arg if arg[0] == deno, and at the second arg for node.

This is significantly complicated for various reasons:

  • the first arg may not be called deno or node. It may be called deno.exe, or node-canary, or whatever really
  • because both node and Deno permit flags in between the deno run / node and <filename>, tools need to know to ignore anything after node / deno run that starts with a -- until you've reached the file path. This is then further complicated for args that do not require = to associate values (such as deno run --seed 123 <filename>). As a tool you'd need to be aware of all flags of deno run, their associativity rules, and reimplement this in your library. This is infeasible to expect from users, and also puts an undue burden on runtimes to not introduce new flags that don't require = to associate values.

I think exposed args should be an array of all string arguments intended to be passed to the user code. Runtimes should themselves define what "intended to be passed to the user code" means. In Deno and Node this would mean all flags after <filename>. We can add some examples to the spec to explain intention here.

@CanadaHonk
Copy link
Member Author

I agree, although it could possibly also be useful to expose the raw argv or binary path or runtime args somewhere too, just not as the main args API, eg checking if a runtime's flag was used or not. However, that could be left to each runtime to do how it wants(/already is?) without being standardized here.

@lucacasonato
Copy link
Member

Yeah - I think exposing arg information passed to runtimes is better done in runtime specific APIs that present this as structured data. Otherwise you run into the arg parsing problem anyway

@bakkot
Copy link

bakkot commented Feb 7, 2024

Some prior discussion in the repo which eventually became node's util.parseArgs.

Fun fact: util.parseArgs actually does the "strip runtime parts" thing internally, since you don't actually want to parse those things in an arg parser. It just never ended up getting exposed to users.

@styfle
Copy link

styfle commented Feb 8, 2024

I agree, although it could possibly also be useful to expose the raw argv or binary path

I think that the args API can be separate from the binary path API. For example, see process.execPath which is common when forking the process.

@CanadaHonk
Copy link
Member Author

I agree, I put in the explainer/readme but forgot to put here. It seems best to leave aspects like that intentionally not standardized and allow implementers to do so in their own APIs as they see fit.

@paperdave
Copy link

i think it was a silly choice to make process.argv contain the binary path to the runtime as well as the script path (it isn't always guaranteed to be set in some extreme edge cases).

i dont think there is any use case in having a standard way to expose runtime args (aka process.execArgv) because these are platform dependant, and branching on that is runtime-dependant code (the flags to a runtime should not be standardized)

it would be nice to have a way to get the name of the script being run (think help messages that explain a usage like "${arg0} [options]"). import.meta.url is standardized already. taking the basename of the url works in most situations, but one edge case here is if you have a file named a that is a symlink to b.js and contains a shebang like #!/usr/bin/env node, you will want to see "a", but import.meta.url will probably print out the path to b.js.

i dont know if this situation actually has a good solution right now, i notice bun build --compile sets process.argv0 to the desired value but obviously this doesnt work outside of the bundled binary (point's to bun/node) or with shebangs.

@CanadaHonk CanadaHonk added the agenda+ Should be discussed next meeting label Mar 7, 2024
@tmikov
Copy link

tmikov commented Mar 7, 2024

The intuitive approach is to store the script name in argument zero, similar to Python. It follows the existing conventions. For use cases that don't need it, it is easy to ignore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
agenda+ Should be discussed next meeting spec
Projects
None yet
Development

No branches or pull requests

6 participants