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

Implement notion shim command #100

Merged
merged 9 commits into from
Jul 26, 2018
Merged

Implement notion shim command #100

merged 9 commits into from
Jul 26, 2018

Conversation

mikrostew
Copy link
Contributor

@mikrostew mikrostew commented Jul 20, 2018

Implements notion shim

List shims

Running notion shim lists the shims that exist in ~/.notion/bin:

$ notion shim
yarn
eslint
node
npx
npm

Running notion shim --verbose lists those shims and where they will resolve to:

# in a project where Notion is configured
$ notion shim -v
yarn -> /Users/mistewar/.notion/versions/yarn/1.2.0/bin/yarn
eslint -> /Users/mistewar/src/notion/crates/notion-core/fixtures/basic/node_modules/.bin/eslint
node -> /Users/mistewar/.notion/versions/node/6.11.1/bin/node
npx -> [shim not implemented!]
npm -> /Users/mistewar/.notion/versions/node/6.11.1/bin/npm

# when Notion is not configured
$ notion shim -v
yarn -> [system]
eslint -> [system]
node -> [system]
npx -> [shim not implemented!]
npm -> [system]

# when node or yarn has not been installed locally
$ notion shim -v
yarn -> [will install version = 1.3]
eslint -> /Users/mistewar/src/notion/crates/notion-core/fixtures/basic/node_modules/.bin/eslint
node -> [will install version = 6.11.3]
npx -> [shim not implemented!]
npm -> [will install version = 6.11.3]

Create shims

Running notion shim <name> creates a 3rd-party executable shim in the notion shim dir (~/.notion/bin/ on unix), pointing to .notion/launchbin:

$ notion shim foo
$ ls -og ~/.notion/bin/
total 22504
lrwxr-xr-x  1        33 Jul 23 13:11 foo -> /Users/mistewar/.notion/launchbin
lrwxr-xr-x  1        33 Jul 20 14:20 eslint -> /Users/mistewar/.notion/launchbin
-rwxr-xr-x  1   5946580 Jul 20 11:57 node
lrwxr-xr-x  1        36 Jul 20 11:57 npm -> /Users/mistewar/.notion/launchscript
lrwxr-xr-x  1        36 Jul 20 11:57 npx -> /Users/mistewar/.notion/launchscript
-rwxr-xr-x  1   5572172 Jul 20 11:57 yarn

# creating a shim that already exists shows an error
$ notion shim foo
error: shim `foo` already exists

Delete shims

Running notion shim <name> --delete deletes a 3rd-party executable shim:

$ ls -go ~/.notion/bin/
total 22504
lrwxr-xr-x  1        33 Jul 20 14:20 eslint -> /Users/mistewar/.notion/launchbin
lrwxr-xr-x  1        33 Jul 23 15:12 foo -> /Users/mistewar/.notion/launchbin
-rwxr-xr-x  1   5946580 Jul 20 11:57 node
lrwxr-xr-x  1        36 Jul 20 11:57 npm -> /Users/mistewar/.notion/launchscript
lrwxr-xr-x  1        36 Jul 20 11:57 npx -> /Users/mistewar/.notion/launchscript
-rwxr-xr-x  1   5572172 Jul 20 11:57 yarn

$ notion shim foo --delete
$ ls -go ~/.notion/bin/
total 22504
lrwxr-xr-x  1        33 Jul 20 14:20 eslint -> /Users/mistewar/.notion/launchbin
-rwxr-xr-x  1   5946580 Jul 20 11:57 node
lrwxr-xr-x  1        36 Jul 20 11:57 npm -> /Users/mistewar/.notion/launchscript
lrwxr-xr-x  1        36 Jul 20 11:57 npx -> /Users/mistewar/.notion/launchscript
-rwxr-xr-x  1   5572172 Jul 20 11:57 yarn

# errors if it doesn't exist, or you try to delete the non-3rd-party shims
$ notion shim foo --delete
error: shim `foo` does not exist
$ notion shim npm --delete
error: cannot delete `npm`, not a 3rd-party executable

Closes #96.

@mikrostew mikrostew changed the title [WIP] Implement notion shim command Implement notion shim command Jul 24, 2018
@mikrostew mikrostew requested review from dherman, monshi and benblank July 24, 2018 20:12
Copy link
Collaborator

@dherman dherman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just one request to refactor a deep function.

}
}

fn list(session: &mut Session, verbose: bool) -> Fallible<bool> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is hard to read. Can you break out some of the nested loops into helper functions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Copy link
Collaborator

@dherman dherman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more feedback... hang in there, this is good progress and a good opportunity to pick up some good Rust style. We're getting there!

@@ -100,38 +108,41 @@ Options:
}
}

fn list(session: &mut Session, verbose: bool) -> Fallible<bool> {
fn list(session: &Session, verbose: bool) -> Fallible<bool> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an improvement! But there are still a few things we can do to make it simpler. First a few general points:

  • You should generally avoid inspecting error cases, and just propagate them.
  • You should generally prefer let foo = bar()?; to bar().map(|foo|, { ... }). This avoids rightward drift, avoids confusing iteration map versus result map, and lets you code closer to a style that's like exceptions. As an analogy in JS, this is why let foo = await bar(); is nicer than bar.then((foo) => { ... }).
  • It's easiest to just convert foreign error types like io::Error into notion's error types as early as possible, and the ? syntax makes that lightweight. So instead of returning Result<Foo, io::Result> from helper functions, just return Fallible<Foo>.

As for the Command trait, don't throw away errors and return Ok(false) -- you want to let the particular error propagate out.

Here's how we could write this function to be simpler and more readable/maintainable:

fn list(session: &Session, verbose: bool) -> Fallible<()> {
    let shim_dir = path:shim_dir()?;
    let files = fs::read_dir(shim_dir).unknown()?;

    for file in files {
        print_file_info(f, session, verbose)?;
    }

    Ok(())
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is so much simpler!

I made peace with the borrow checker, but lately I have been fighting Result and Option. This helps a lot!

session: &Session,
verbose: bool,
) -> Result<bool, io::Error> {
file.path().file_name().map_or(Ok(false), |shim_name| {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A DirEntry always has a file name, so instead of using the Option that comes from file.path().file_name() you can use file.file_name() which directly returns an OsString.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doh! I missed that in the docs somehow

match resolve_shim(session, &shim_name) {
Ok(shim_info) => println!("{} -> {}", shim_name.to_string_lossy(), shim_info),
Err(err) => {
style::display_error(style::ErrorContext::Notion, &err);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want to be doing this error handling logic here, as opposed to letting it propagate out and be handled at the top level.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

})
}

fn print_file_info(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's a simplified version of this function:

fn print_file_info(file: fs::DirEntry, session: &Session, verbose: bool) -> Fallible<()> {
    let shim_name = file.file_name();

    if verbose {
        let shim_info = resolve_shim(session, &shim_name)?;
        println!("{} -> {}", shim_name.to_string_lossy(), shim_info);
    } else {
        println!("{}", shim_name.to_string_lossy());
    }

    Ok(())
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So much better!

@@ -152,13 +163,18 @@ fn resolve_shim(session: &mut Session, shim_name: &OsStr) -> Fallible<ShimKind>
}
}

fn node_is_available(project: &Project, session: &Session) -> Fallible<Option<Version>> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this isn't a boolean predicate, maybe a better name would be something like available_node_version?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree that's a better name

Copy link
Collaborator

@dherman dherman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great.

@dherman dherman merged commit a64b114 into volta-cli:master Jul 26, 2018
@mikrostew mikrostew deleted the shim-cmd branch December 13, 2018 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

notion shim
2 participants