-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
First pass on running subprocesses #1156
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool! Needs tests
5b01989
to
044c148
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple comments. 🎉 was wanting this!
0478a78
to
79142ea
Compare
01c6ce7
to
f50a3fe
Compare
f493418
to
24002b0
Compare
https://code.visualstudio.com/docs/editor/tasks-appendix#_schema-for-tasksjson ^-- Also uses a CommandOptions interface |
Very nice! Be sure to add that link in the source code so we maintain compatibility. |
I've refactored this API into two ops, so that child processes can be stored on the resources table. I'm not so happy with all these different names "Command", "Run", "Child". I think we should use a single name for all these concepts. Does anyone have opinions on this? |
5a09bf8
to
0ad8c3f
Compare
There is a lot to consider in this interface. We should name carefully. There are two distinct things to name in the low-level interface - the function which starts the subprocess - and the name of the subprocess object (a noun). Furthermore have the name of the command-line argument/permission. Ideally we want to introduce as few names as possible, we also want to be intelligible to people coming from different languages. Here are a few options. Option 1 Just call everything subprocess. Familiar to python people, correct terminology-wise. However it's very long.
Option 2 Use "Subprocess" for the object but use "exec()" for the function. Exec isn't exactly right, as it has a fairly specific meaning - which we might want to expose at some point (but probably not). However it's short.
Option 3 Use "Process" for the object but use "run()" for the function. run is short and doesn't overload concepts in Node. (Current naming)
|
We have I would vote for Option 1. It is clear in intent. The only other thought is going less functional and more class based and simply. I guess how much consistency do we want between constructors or factories for things? const p = new Subprocess({ args: ["python"] });
let status = await p.status();
p.close(); |
0bcaaaa
to
f12b112
Compare
js/subprocess.ts
Outdated
} | ||
} | ||
|
||
export interface SubprocessStatus { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This type doesn't properly capture that either code
or signal
will have a value.
Thus the user won't be able to do:
declare function handleExitCode(code: number);
declare function handleExitSignal(sig: number);
if (status.code != null) {
handleExitCode(status.code);
} else {
handleExitSignal(status.signal);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That code works currently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I concede -- It works because we using typescript in sloppy mode.
OK for now then.
base: &msg::Base, | ||
data: &'static mut [u8], | ||
) -> Box<Op> { | ||
assert!(base.sync()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@piscisaureus Note that it is fundamentally sync. I don't think it blocks tho. Can you elaborate on your problem with it being sync?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay if we hereby agree that RIDs should be assigned in on the JS side and not on the rust side and we'll make that in a follow-up patch.
Otherwise this adds a low level API that is fundamentally sync, which I will not approve.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue is that run() cannot return until the rust side has assigned a RID to the to the SubProcess object.
So that gets in the way op queuing/batching, out-of-process backend etc. that we may want to do in the future.
I'm not against sync ops but I am against ops that can only be sync.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I see what you mean. Yes, in order to support "dispatchv" we would need to allocate RIDs on the JS side. I'm ok with that. However there are many places currently where we're allocating RIDs and I think we should change them all to be allocated in JS at once. Therefore I'd argue in favor of keeping this as it is for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, in order to support "dispatchv" we would need to allocate RIDs on the JS side. I'm ok with that.
Ok, then we're golden.
js/subprocess_test.ts
Outdated
test(async function runPermissions() { | ||
let caughtError = false; | ||
try { | ||
deno.run({ args: ["python", "-c", "print('hello world')"] }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other tests are using imported run function, but this one uses deno.run
. I suggest using deno.run
in all tests since it's better shows how deno's public api is used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Can't approve since it's my own PR.
I want to propose the following API. Which is based very closely on Go.
Or if you want to start it and later wait for it to complete
Setting environmental variables (which won't be done in this patch)
For stdin, stdout, stderr we would do the following to inherit from the parent process
Or to do the "piped" behavior
The Go API supports assigning an arbitrary File (in our case deno.File) to the stdio properties. We would not be able to achieve that with the current implementation of tokio_process.... But I think we should strive for ideal APIs and just die with I think this API is straightforward and well thought-out. (Like most Go APIs.) It makes sense given how many other Go-inspired APIs we're using. It provides guidance in the future when expanding it (like in the case of env) |
Go also has a lower-level API: https://golang.org/pkg/os/#Process
|
This is pretty similar to nodejs' spawn() api, except that here argv[0] is explicit. startProcess({
exe: "/usr/bin/python", // Optional; if omitted, will be taken from args[0]
args: ["python", "-c", "print 'hi'"],
cwd: "/tmp"
}); |
I would argue that the Although it's not a very important use-case, it's worth noting that argv[0] can be different than the executed program. So it makes sense for the low-level API to separate the two concepts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM - let's land this very useful patch and leave open the possibility for reworking these APIs later. I outlined my proposal in a comment above - after this is landed I will start an issue where we can discuss further.
Changes since v0.1.12: - First pass at running subprocesses (denoland#1156) - Improve flag parsing (denoland#1200) - Improve fetch() (denoland#1194 denoland#1188 denoland#1102) - Support shebang (denoland#1197)
No description provided.