-
Notifications
You must be signed in to change notification settings - Fork 39
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
Add skeleton reimplementation of sandboxfs in Rust #23
Conversation
# For testing the Rust implementation, we only need to build the tests using | ||
# one Go version. | ||
- env: DO=rust | ||
go: 1.8 |
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.
Given that stable is 1.10, are you sure you want to pin back to 1.8?
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.
Note that this is an exclusion and it's actually saying "for the Rust build, don't bother using Go 1.8". Thanks Travis for making this so obvious!
I guess I should update the configuration to use 1.10 now, but let's not conflate that change with this review ;-)
# pass all integration tests. This blacklist keeps track of which those are. | ||
# Ideally, by the time this alternative implementation is ready, this list | ||
# will be empty and we can then refactor this file to just test one version. | ||
local blacklist=( |
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 feel like there should be an issue tracking the progress on this blacklist that is linked from this comment.
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.
Maybe. But this project (including the previous implementation) is all experimental and under active development. I don't see much value in tracking this in a bug at this point.
admin/travis-build.sh
Outdated
TestSignal_QueuedWhileInUse | ||
) | ||
|
||
# TODO(jmmv): Replace by a Bazel-based build once the Rust rules are |
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.
Link to an open issue in a tracker somewhere?
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.
Done.
|
||
# Compute the list of tests to run by comparing the full list of tests that | ||
# we got from the test program and taking out all blacklisted tests. This is | ||
# O(n^2), sure, but it doesn't matter: the list is small and this will go away |
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 could use associative arrays if you know it's bash.
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.
Unfortunately, macOS's ancient /bin/bash
(3.2.57) doesn't support this feature and we do have a Travis build on macOS. (I haven't double-checked if Travis installs a newer bash; maybe it does, but I'm lazy and don't think it's super-important to improve this.)
done | ||
set -x | ||
|
||
[ "${#valid[@]}" -gt 0 ] || return 0 # Only run tests if any are valid. |
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 check is unnecessary. The for loop won't do anything on an empty array.
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.
Yeah... I'm not even sure why I wrote this. I must have had some extra code in the past that evaluated to non-zero and caused set -e
to fail the build.
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, I remember now. Removed this line and Travis started failing again:
./admin/travis-build.sh: line 179: valid[@]: unbound variable
I've seen bugs in macOS's ancient bash that cause this, but I'm a bit surprised to see that Linux is failing as well.
src/main.rs
Outdated
|
||
impl From<io::Error> for MainError { | ||
fn from(err: io::Error) -> Self { | ||
MainError::Runtime(format!("{}", 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.
io::Error should probably be embedded instead of flattened. Consider using withoutboats's failure crate to automate this logic.
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 trying to figure this one out... but because GitHub didn't let me batch replies... writing this reply to avoid confusion.
src/main.rs
Outdated
/// Obtains the program name from the execution's first argument, or returns a | ||
/// default if the program name cannot be determined for whatever reason. | ||
fn program_name(args: &[String], default: &'static str) -> String { | ||
args.get(0) |
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.
Long chains like this are hard to read. Instead, break out of the monad early and use regular code.
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. Somehow I thought this was common style in Rust as I've seen it in many places... but glad to see I'm not the only one thinking it's hard to read.
I've replaced this with a match chain... which maybe is also hard?
src/main.rs
Outdated
.unwrap_or(default.to_string()) | ||
} | ||
|
||
/// Prints program usage information to stdout. |
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.
Usage is generally printed to stderr, not stdout.
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.
No. That gets in the way of sandboxfs --help | grep foo
, which is very frustrating. Note that I'm only printing usage when explicitly asked to, and when that's the case, the output belongs in stdout because that's what the user asked; it's not an error.
Self-citation: http://julio.meroh.net/2013/08/cli-design-requesting-and-offering-help.html
src/main.rs
Outdated
process::exit(1); | ||
}, | ||
Err(MainError::Usage(message)) => { | ||
eprintln!("Usage error: {}", message); |
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'm not sure this message needs to be prefixed.
src/main.rs
Outdated
}, | ||
Err(MainError::Usage(message)) => { | ||
eprintln!("Usage error: {}", message); | ||
eprintln!("Type {} --help for more information", program); |
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.
Why not just print the usage at this point?
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.
Because I find it incredibly annoying to have a long usage message printed when I didn't ask for one. Such a long message clobbers the actual problem that triggered this because that first line vanishes among the noise.
Alright. I think I have addressed everything. But oh what a mess GitHub is. I can't tell why I couldn't bundle all replies to your commits in one "review step" and instead had to reply to them individually. I'm sure you have received too many notifications... |
.collect::<Vec<&OsStr>>(); | ||
let fs = SandboxFS::new(); | ||
info!("Mounting file system onto {:?}", mount_point); | ||
fuse::mount(fs, &mount_point, &options) |
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.
Ugh, this is a bug in their API. They're requesting &P instead of P, but forgot to specify ?Sized. Honestly, they should probably not be requesting &P, since they're indirecting via AsRef.
src/main.rs
Outdated
Err(MainError::Usage(message)) => { | ||
eprintln!("Usage error: {}", message); | ||
if let Err(err) = safe_main(&program, &args[1..]) { | ||
if let Some(err) = err.cause().downcast_ref::<UsageError>() { |
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 downcast_ref the error directly.
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 can't figure out what you mean by this... (and especially not after a month since I dealt with this code).
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.
remove .cause()
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 see. Done.
Thanks again for reviewing this and apologies for the long delay in getting back to this change. Have been mostly on vacation since then. |
.collect::<Vec<&OsStr>>(); | ||
let fs = SandboxFS::new(); | ||
info!("Mounting file system onto {:?}", mount_point); | ||
fuse::mount(fs, &mount_point, &options) |
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.
Alternatively you could just add ?Sized to their constraint: P: AsRef<Path>+?Sized
This change adds a barebones reimplementation of sandboxfs in Rust. As things are now, the new version does nothing: it just provides trivial command-line processing and mounts an empty FUSE file system. However, this change puts all pieces in place to continue development of this new version. In particular, this adjusts the Travis CI configuration to support running the exact same integration tests as we run for the Go implementation against the new code, and currently blacklists all of them because the new code passes none.
Ping @mhlopko for Bazel project review. |
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.
Thought I've lgtmed this already.
}, | ||
None => 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.
Personally I find using the methods on Option much easier to understand: https://rust.godbolt.org/z/sGTXht
You can also return a &str
to save an allocation but it probably isn't worth it in this case: https://rust.godbolt.org/z/7wGCfT
&matches.free[0] | ||
} else { | ||
return Err(Error::from(UsageError { message: "invalid number of arguments".to_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.
Personally I think it would be easier to read with the failure first.
if matches.free.len() != 1 {
return Err(...)
}
let mount_point = &matches.free[0];
use std::env; | ||
use std::path::Path; | ||
use std::process; | ||
use std::result::Result; |
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 in the prelude and shouldn't have to be imported explicitly.
This change adds a barebones reimplementation of sandboxfs in Rust.
As things are now, the new version does nothing: it just provides
trivial command-line processing and mounts an empty FUSE file
system.
However, this change puts all pieces in place to continue development
of this new version. In particular, this adjusts the Travis CI
configuration to support running the exact same integration tests as
we run for the Go implementation against the new code, and currently
blacklists all of them because the new code passes none.