-
Notifications
You must be signed in to change notification settings - Fork 22
Conversation
- Add a CommandBridge which is a testable command builder - Move Target struct in its own module - Add cargo::commands module which contains the logic of building cargo commands
I am currently is quite puzzled by the compilation error if I uncomment the line 35 of |
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 always like a good refactor. I left some comments but this is definitely a good stab at making the commands more flexible. I'd also like to hear what @steveklabnik and @euclio think as well.
key_str.push(key.as_ref()); | ||
value_str.push(value.as_ref()); | ||
|
||
self.env.insert(key_str, value_str); |
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.
You can just use to_os_string
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.
ooh, I missed that. I am not familiar with the OsStr(ing)?
interface
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.
People tend to miss it. The Standard Library docs are great! Usually I'll take a look before using something to see what's available, especially if I tend to do common patterns like conversions!
src/cargo/command_bridge.rs
Outdated
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self { | ||
let mut os_string = OsString::new(); | ||
os_string.push(arg); | ||
self.args.push(os_string); |
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.
Again to_os_string
would be better. Since you keep turning them into OsStrings why not just accept something like Into<OsString>
and calling into
?
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.
You are probably right. I was mirroring the interface of std::process::Command
without thinking of making my life easier.
I'll test that.
src/cargo/command_bridge.rs
Outdated
pub fn new(name: &str) -> Self { | ||
CommandBridge { | ||
name: String::from(name), | ||
.. Default::default() |
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 is such a neat trick!
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.
Ah ! Now that you say it, yes it is. Very useful to replace factories in tests: implement Default
and only specify the field you want to test.
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'll be leveraging this in some of my own stuff now!
src/cargo/command_bridge.rs
Outdated
self | ||
} | ||
|
||
pub fn stderr<S: Into<Stdio>>(&mut self, stderr: S) -> &mut Self { |
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.
Is this supposed to be Into<Stderr>
?
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.
honestly I just mirrored the std::process::Command interface. I imagine Stdio
is a reference to the libc streams from stdio.h
. I didn't took the time to look for Into<Stdio>
implementors as I need to stay compatible with std::process::Command anyway.
If you have any suggestion, I'll take it
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 looked at the docs. I think it's Stdio as the type so this is fine, but this also means you can put an StdIn where there should be an StdErr.
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 this is legal. In this case on Linux it's equivalent to passing it /dev/null
as stdin
is often closed for writing (not always though, in this case it's a blocking read for eternity)
src/cargo/command_bridge.rs
Outdated
} | ||
|
||
pub fn to_command(self) -> Command { | ||
let mut command = Command::new(self.name); |
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 don't think name
is the best choice to describe this. I think command
would be better but that looks kind of weird here.
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.
good point. command_name
it is
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.
Awesome thanks! :D
src/cargo/command_bridge.rs
Outdated
cmd.stderr(stderr); | ||
// assert | ||
// FIXME: is there is really no way to compare an Stdio instance ?? | ||
//assert_eq!(stderr as *const (), cmd.stderr.unwrap() as *const ()) |
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.
You can turn them into RawFd which is basically just a c_int and compare them.
https://doc.rust-lang.org/std/os/unix/io/type.RawFd.html
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.
Since it implements this it also implies that it implements the into version of it.
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.
Oh ! Good catch ! Thank you ! :)
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.
You're welcome :D
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's in std::os::unix though, what about windows?
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 dug into the libstd source and couldn't find anything windows specific. This won't work on appveyor.
src/cargo/commands.rs
Outdated
|
||
pub fn retrieve_metadata(manifest_path: &Path) -> CommandBridge { | ||
let mut command = CommandBridge::new("cargo"); | ||
command.arg("metadata") |
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'd prefer it to be a builder pattern stylistically so you can do:
CommandBridge::new("cargo")
.arg("metadata")
.arg("--manifest-path")
.arg(manifest_path)
.arg("--no-deps")
.arg("--format-version")
.arg("1")
If you change the function arg
to arg(self) -> Self
this enables that pattern. Builder patterns are great and this is essentially what you're doing here! :D
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, it would be more canonic. I'll change
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.
:D
src/cargo/commands.rs
Outdated
command.arg("--verbose"); | ||
} | ||
|
||
//match target.kind { |
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.
Did you take this out?
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.
still in the WIP :)
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.
Ah got it cool
src/cargo/commands.rs
Outdated
.stdout(Stdio::null()); | ||
|
||
if is_verbose { | ||
command.arg("--verbose"); |
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.
Hmmm this would cause command to be consumed if you did what I mentioned. You'd have to do a let command = command.arg("--verbose");` here
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.
👍
assert!(res.is_err()) | ||
} | ||
} | ||
} |
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.
Is this whole file new because it got moved?
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.
nope, the file is new. I extracted the logic of command building here and I want to unit test it
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.
Even better. I'm all for more tests. Looking forward to seeing the end result :D
/// This temporary struct is used to inspect the generated command before calling the process::Command | ||
/// builder, as we can't inspect its structure and make assertions on it | ||
#[derive(Debug, Default)] | ||
pub struct CommandBridge { |
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.
Just another use case for rust-lang/rust#44434 😞
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.
:( If only. Might need an RFC?
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, this is much needed. And std::{fs, io}
stubbing. So much of that
Hmmm tests are failing but it doesn't seem to be your fault (I think). These changes look great! :D |
I like this idea in general, but yeah, the tests seem to be failing. do they pass locally? Given that both travis and appveyor fail with the same message, I suspect that it's something in here... |
Sorry, not much time to work on it recently. I am still up to finish this PR, but I would understand if you close it. I can always work on it offline and re-submit it later, rebased from master. |
It happens! I go for a long time without having time too. I am going to give this a close though, if you or anyone else wants to update it, please submit a new PR! Thanks :) |
I push this PR now for easier review + early discussions.
Todo:
Command
bridge that we can inspect before calling the trueCommand
builderutils
module, used by the cargo moduleEDIT: Oh I forgot to add my new nick I got from the RustFest:
Sincerly,
The Test Dude