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

feat: Add Java Module #314

Merged
merged 12 commits into from
Sep 19, 2019
Merged

Conversation

jakubclark
Copy link
Contributor

@jakubclark jakubclark commented Sep 8, 2019

Implemented a basic Java module, that shows the Java version, when inside a Java/Maven Project.

Description

  • New module java that calls javac --version, to get the version of Java
  • Simple tests for the formatting and call to javac
  • Updated the Dockerfile to install Java

Motivation and Context

Just another language that can be supported.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Screenshots (if appropriate):

MacOS:
java_mac

Linux (WSL):
java_wsl

How Has This Been Tested?

  • I have tested using MacOS
  • I have tested using Linux
  • I have tested using Windows

Checklist:

  • I have updated the documentation accordingly.
  • I have updated the tests accordingly.

Copy link
Contributor

@chipbuster chipbuster left a comment

Choose a reason for hiding this comment

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

Hey @jakubclark, thanks for the PR!

This is looking pretty good already. You'll need to make a few minor changes due to a new PR that just got merged (sorry about the crummy timing) and there are a few questions I have, but the code is almost ready to merge (aside from those annoying version number issues you seem to be running into).

src/print.rs Show resolved Hide resolved
tests/testsuite/java.rs Outdated Show resolved Hide resolved
src/modules/java.rs Show resolved Hide resolved
src/modules/java.rs Outdated Show resolved Hide resolved
src/modules/java.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@chipbuster chipbuster left a comment

Choose a reason for hiding this comment

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

Just a few minor styling + comment nitpicks and then we'll be good to go, I think!

| Variable | Default | Description |
| ---------- | -------------- | -------------------------------------------------------- |
| `symbol` | `"☕ "` | The symbol used before displaying the version of Java. |
| `style` | `"bold RGB(166, 42, 42)"` | The style for the module. |
Copy link
Contributor

Choose a reason for hiding this comment

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

The syntax for colors is #RRGGBB, so the style would be bold #a62a2a

Copy link
Member

Choose a reason for hiding this comment

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

I think built-in modules should probably all use the 16 ANSI colors to remain compatible with as many emulators and configurations as possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, I can change it to be red instead.

Copy link
Contributor

Choose a reason for hiding this comment

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

Didn't think about that. This is probably right. The color appears to be a darker version of the red color, perhaps dimmed red would be a good color?

docs/config/README.md Show resolved Hide resolved
@jakubclark
Copy link
Contributor Author

@chipbuster I've addressed your comments. Let me know if there is anything else to change!

@chipbuster
Copy link
Contributor

@jakubclark I'm really sorry about this, I should have done this a little sooner. I just pulled and tested the prompt from your fork, and the addition of the java module tanks performance.

To give you an idea, we can get directory, git branch, git status, package, rust, and python info in 28ms, but adding a single java file raises that to 137.3ms.

image

Do you have any ideas on how we could potentially mitigate this timing problem? I can tell you that it's definitely noticeable--the reason I reached for hyperfine was because I was surprised at how slow the prompt felt.

Maybe it would be possible to parse the information out of java -version instead?

With the current speeds I'm seeing, I don't think we can justify putting this module into the prompt :\

@jakubclark
Copy link
Contributor Author

@chipbuster I'll try getting the version from java -version.

I just chose javac because the output was simpler.

I'll do some performance testing and post the results here.

@chipbuster
Copy link
Contributor

@jakubclark Thanks. I think the number we'd love to hit for java module render (via starship module java) would be 35-40ms, but 50 might be tolerable. Anything higher than that will most likely be questionable.

@jakubclark
Copy link
Contributor Author

@chipbuster Unfortunately, using java -version doesn't help much:

Screenshot 2019-09-08 at 19 47 34

Looks like java -version and javac -version are simply not fast enough.

@chipbuster
Copy link
Contributor

@jakubclark Damn 😞

Unfortunately, while we're building towards support for several things that could help to mitigate this, like disabled-by-default modules, timeouts, caching data, and (perhaps someday) asynchronous rendering, none of those are quite ready at the moment. I'm afraid we might have to put this PR on hold until one of those comes in.

If you figure out some way to get the module time down without those, let us know and we'll be happy to merge this in!

@nickwb
Copy link
Contributor

nickwb commented Sep 8, 2019

I had a similar issue when I tried to implement #182 - I'm considering implementing the version detection myself 😅

@matchai matchai added the on hold Progress on this issue or PR is currently suspended. label Sep 9, 2019
@hdevalke
Copy link

@chipbuster Unfortunately, using java -version doesn't help much:
Looks like java -version and javac -version are simply not fast enough.

At least on OSX the openjdk jvm installed a release file, I was able to get the version number under 5ms.

❯ hyperfine "cat $JAVA_HOME/release | grep JAVA_VERSION | grep -Eo '[0-9]+\\.[0-9]+\\.[0-9]+'"
Benchmark #1: cat /Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/release | grep JAVA_VERSION | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+'
  Time (mean ± σ):       3.2 ms ±   0.1 ms    [User: 2.6 ms, System: 4.2 ms]
  Range (min … max):     3.0 ms …   4.3 ms    566 runs

If JAVA_HOME is not set this could be used

❯ hyperfine "cat $(/usr/libexec/java_home)/release | grep JAVA_VERSION | grep -Eo '[0-9]+\\.[0-9]+\\.[0-9]+'"
Benchmark #1: cat /Library/Java/JavaVirtualMachines/jdk-12.0.1.jdk/Contents/Home/release | grep JAVA_VERSION | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+'
  Time (mean ± σ):       3.3 ms ±   0.7 ms    [User: 2.7 ms, System: 4.3 ms]
  Range (min … max):     3.0 ms …  16.1 ms    491 runs

Not sure for other OSes but caching java -version to some file could help to create a generic solution

@hdevalke
Copy link

hdevalke commented Sep 18, 2019

Just found out there is an option -Xinternalversion this is the output on my mac:

❯ hyperfine  'java -Xinternalversion'
Benchmark #1: java -Xinternalversion
  Time (mean ± σ):      24.2 ms ±   7.3 ms    [User: 12.5 ms, System: 8.5 ms]
  Range (min … max):    22.4 ms …  69.8 ms    41 runs

On my Linux it is even below 5ms.

I tried to add this functionallity, but more testing is needed. hdevalke@51428ed

@chipbuster
Copy link
Contributor

chipbuster commented Sep 19, 2019

@hdevalke I think the -Xinternalversion option will be workable, even though parsing the output will be one hell of a task (our main restriction is process launch time, not Rust runtime, so the cost will be code complexity, not runtime).

Assuming the existence of any paths is a slightly dicey proposition, because we're making it a goal to (eventually) support all OSses, including things like BSDs, Windows, and Android (in Termux), so I'd prefer not to go for the JAVA_HOME or libexec options, but we can try to fall back to those if the internal version turns out to be unparseable.

@jakubclark Would you still be interested in working on this?

@jakubclark
Copy link
Contributor Author

jakubclark commented Sep 19, 2019

@chipbuster @hdevalke I'll try using java -Xinternalversion to extract the Java version using regular expressions from inside Rust and what's already been done in hdevalke@51428ed.

Get java version from internalversion system property
@jakubclark
Copy link
Contributor Author

After making the necessary changes, here are the results from my mac:

Screenshot 2019-09-19 at 19 43 19

@chipbuster
Copy link
Contributor

@jakubclark
image

I get no noticeable difference on my Linux machine either. Looks like we got that timing issue nailed! Great work, and thanks to @hdevalke for the hint!

Do you know if this works cross-platform with both OpenJDK/JRE and Oracle Java? I can try to test this out in a docker container later if you don't know.

}

fn get_java_version() -> Option<String> {
match Command::new("java").arg("-Xinternalversion").output() {

Choose a reason for hiding this comment

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

Should we take into account the JAVA_HOME variable?
If exists the version could be $JAVA_HOME/bin/java -Xinternalversion.
When using maven it will take priority over the java binary in the PATH.

Copy link
Contributor

Choose a reason for hiding this comment

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

I like this idea. I'm not a fan of relying on JAVA_HOME being set (simply because half the envars that really ought to be set usually aren't), but I think checking for the existence of a JAVA_HOME variable should be more than fast enough.

Do you know if that variable gets set on Windows as well, or is that a UNIX-like-only thing?

Copy link
Contributor

Choose a reason for hiding this comment

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

Answer to my own question: it seems like (as with many envars) it's supposed to be set on windows, but a lot of installers fail to do so.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think it's necessary to check $JAVA_HOME. Running $JAVA_HOME/bin/java -Xinternalversion should be identical to running java -Xinternalversion. If java isn't on the PATH environment variable, then Java simply isn't set up properly.

Copy link
Contributor

Choose a reason for hiding this comment

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

That's to say that if you set up a (maven?) environment, the PATH should automatically modify to put the newly-versioned Java binary first?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

https://www.baeldung.com/maven-java-home-jdk-jre

First checks $JAVA_HOME, otherwise defaults to java on the $PATH.

But I've never had to set up separate Java installations and setting up $JAVA_HOME for different projects...

So maybe we should follow the same strategy as Maven:

Check for $JAVA_HOME.
Otherwise just use the java that is on the $PATH.

@chipbuster chipbuster added in progress ✨ enhancement A new feature implementation. and removed on hold Progress on this issue or PR is currently suspended. labels Sep 19, 2019
@jakubclark
Copy link
Contributor Author

jakubclark commented Sep 19, 2019

@chipbuster I have Oracle Java installed and it works for me.

Also, the result of running java -Xinternalversion on my raspberry pi (which has Oracle Java version 1.8) is here.

So I think it's safe to say that this works for both OpenJDK and Oracle versions.

@chipbuster
Copy link
Contributor

Alright, excellent.

Looks like our CI is failing the standard test suite, though not the containerized tests...do we potentially have a test somewhere that should be #[ignore]d that isn't?

@jakubclark
Copy link
Contributor Author

For the test suites, I don't know what the issue is. Could be that the result of running java -Xinternalversion might be different than expected, but hard to debug the cause. This is the specific failed test.

@jakubclark
Copy link
Contributor Author

@chipbuster any suggestions on how to debug the Test Suites? I tried printing some data using eprintln!() but it was written to the logs.

@chipbuster
Copy link
Contributor

chipbuster commented Sep 19, 2019

@jakubclark Unfortunately, the CI is not my specialty.

Looking at the logs, it looks like the Java version simply isn't being detected at all (the actual string for the Java version is just a v followed by a color reset code). That suggests to me that the Java version isn't being correctly found.

Perhaps you could try something like

// whatever you need to get the full version string here
let ver = std::command::process("java")...
assert_eq!(ver,"nope");

This will obviously fail, but it'll let you see what's going on when you try call the java binary to get the version.

@hdevalke
Copy link

As this fails on Zulu maybe we could check the length of the version to be not zero:

if end == start {
  None
} else {
  Some(format!("v{}", &java_stdout[start..end]))
}

Support for openjdk could be the MVP, other JVM variants could be added later on.

@hdevalke
Copy link

I tested some other jvm builds:

for image in {azul/zulu-openjdk,adoptopenjdk,amazoncorretto}; do docker run --rm $image java -Xinternalversion; done
OpenJDK 64-Bit Server VM (25.222-b10) for linux-amd64 JRE (Zulu 8.40.0.25-CA-linux64) (1.8.0_222-b10), built on Jul 11 2019 11:36:39 by "zulu_re" with gcc 4.4.7 20120313 (Red Hat 4.4.7-3)
OpenJDK 64-Bit Server VM (12.0.2+10) for linux-amd64 JRE (12.0.2+10), built on Jul 18 2019 14:41:47 by "jenkins" with gcc 7.3.1 20180303 (Red Hat 7.3.1-5)
OpenJDK 64-Bit Server VM (25.222-b10) for linux-amd64 JRE (1.8.0_222-b10), built on Jul 11 2019 20:48:53 by "root" with gcc 7.3.1 20180303 (Red Hat 7.3.1-5)

@jakubclark
Copy link
Contributor Author

I think you're right @hdevalke. It's at least a start.

@jakubclark
Copy link
Contributor Author

Okay, I think this PR is (finally) in a state that it can be merged.

It's able to extract the java version from the java -Xinternalversion command, assuming that the output of the command contains something similar to "JRE (12.0.2+10)". It seems that the most common distributions of Java follow this pattern.

The Zulu distribution that comes with actions/setup-java does not follow this pattern, so an integration test wouldn't work in the CI.

We could include a local copy of the jdkFile from a specific vendor, but I don't think it makes sense to keep an entire JDK in this repo.

Thanks for all your comments and suggestions @chipbuster and @hdevalke !

Copy link
Contributor

@chipbuster chipbuster left a comment

Choose a reason for hiding this comment

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

Minor doc nitpick: do we need to update this?

src/modules/java.rs Outdated Show resolved Hide resolved
docs/config/README.md Outdated Show resolved Hide resolved
Copy link
Contributor

@chipbuster chipbuster left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks for sticking through the (somewhat prolonged) process!

Once this passes CI, we'll go ahead and merge it in.

@jakubclark
Copy link
Contributor Author

At least now we know a number of ways to get the Java version 😄

@chipbuster
Copy link
Contributor

That we do! It's why I love working on these projects--you're never quite sure what you're going to learn next.

@chipbuster chipbuster merged commit 71f03ec into starship:master Sep 19, 2019
@chipbuster
Copy link
Contributor

chipbuster commented Sep 19, 2019

Woo! What a marathon of an issue. Thanks for all your work and for sticking it out!

@all-contributors, please add @jakubclark for code, doc, and tests.

@allcontributors
Copy link
Contributor

@chipbuster

I've put up a pull request to add @jakubclark! 🎉

@chipbuster
Copy link
Contributor

@all-contributors please also add @hdevalke for their invaluable ideas on this PR.

@allcontributors
Copy link
Contributor

@chipbuster

I've put up a pull request to add @hdevalke! 🎉

@jakubclark jakubclark deleted the Implement-Java-Module branch September 19, 2019 23:08
@hdevalke
Copy link

@all-contributors please also add @hdevalke for their invaluable ideas on this PR.

Thank you!

@allcontributors
Copy link
Contributor

@hdevalke

I've updated the pull request to add @hdevalke! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ enhancement A new feature implementation.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants