Skip to content

Instantly share code, notes, and snippets.

@kevin-lee
Last active April 20, 2019 08:47
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save kevin-lee/f1e57b151b5ad08a2a3e to your computer and use it in GitHub Desktop.
Scala Script to create a symbolic link to JDK for Mac OS X
#!/usr/bin/env scalas
/***
scalaVersion := "2.12.8"
logLevel := Level.Warn
*/
// #############################################
// ## Simple Scala script to create ##
// ## a symbolic link to JDK for Mac OS X ##
// ## ##
// ## @author Lee, SeongHyun (Kevin) ##
// ## @version 0.0.1 (2015-04-03) ##
// ## @version 0.1.0 (2019-03-20) ##
// ## @version 0.2.0 (2019-04-20)
// ## ##
// ## https://kevinlee.io ##
// #############################################
import sys.process._
import scala.io.StdIn
import scala.language.postfixOps
object data {
val javaBaseDirPath = "/Library/Java/JavaVirtualMachines"
lazy val javaBaseDir = new java.io.File(s"$javaBaseDirPath")
lazy val Bold = "\u001b[1m"
lazy val normal = "\u001b[0m"
final case class VerStr(major: String, minor: Option[String], patch: Option[String])
implicit object VerStrOrdering extends Ordering[VerStr] {
def compare(x: VerStr, y: VerStr): Int = (x, y) match {
case (VerStr(v1, m1, mn1), VerStr(v2, m2, mn2)) =>
val v = v1.toInt.compare(v2.toInt)
if (v != 0) {
v
} else {
((m1, mn1), (m2, mn2)) match {
case ((None, None), (None, None)) =>
0
case ((None, None), (Some(_), Some(_))) =>
-1
case ((Some(_), Some(_)), (None, None)) =>
1
case ((Some(major1), None), (Some(major2), None)) =>
major1.toInt.compare(major2.toInt)
case ((Some(major1), Some(minor1)), (Some(major2), Some(minor2))) =>
val majorInt1 = major1.toInt
val majorInt2 = major2.toInt
val minorInt1 = minor1.toInt
val minorInt2 = minor2.toInt
val major = majorInt1.compare(majorInt2)
if (major != 0)
major
else
minorInt1.compare(minorInt2)
}
}
}
}
}
import data._
def bold(text: String): String = s"$Bold$text$normal"
def isPositiveNumber(text: String) = text.matches("""[\d]+""")
def help(): Unit = printHelp(Nil)
def printHelp(whatever: List[String]): Unit =
println(s"""
|Usage:
|${bold("ln-s-jdk")} [arguments]
|
| ${bold("-l")}, ${bold("--list")}: list all JDK installed
| e.g.)
| # list JDKs
| ln-s-jdk --list
| ln-s-jdk -l
|
| ${bold("-s")}, ${bold("--slink")} version_number: Create a new symbolic link to the default jdk (i.e. jdk# => actual folder).
|
| # To set the default JDK for Java 9
| ln-s-jdk --slink 9
| ln-s-jdk -s 9
|
| # To set the default JDK for Java 8
| ln-s-jdk --slink 8
| ln-s-jdk -s 8
""".stripMargin)
if (args.isEmpty) {
help()
sys.exit(1)
}
val Command1s = Map("l" -> listAll _, "s" -> slink _, "h" -> printHelp _)
val Command2s = Map("list" -> listAll _, "slink" -> slink _, "help" -> printHelp _)
val argPatter = """([-]+)([\w]+)""".r
(args.toList match {
case argPatter("--", arg) :: rest => Command2s.get(arg).map(_(rest))
case argPatter("-", arg) :: rest => Command1s.get(arg).map(_(rest))
case _ => None
}) match {
case Some(_) =>
println("Done\n")
case None =>
println(s"""
|Unknown args: ${args.mkString(" ")}
|
| # To see available args please run
| ln-s-jdk --help
|
| #or just
| ln-s-jdk
""".stripMargin)
sys.exit(1)
}
def listAll(args: List[String]): Unit = {
println(s"""
|$$ ls -l $javaBaseDirPath
|
|${Process(s"ls -l", Option(javaBaseDir)) !!}
""".stripMargin)
}
def slink(args: List[String]): Unit = {
val version = args match {
case x :: xs => x.trim
case _ => ""
}
if (version.isEmpty || !isPositiveNumber(version)) {
println(s"The argument must be a positive integer. Entered: [${args.mkString(", ")}]")
sys.exit(1)
}
val Before9Pattern = """[^-]+1\.(\d)\.(\d)_(\d+)\.jdk$""".r
val Before9AdoptOpenJdkPattern = """adoptopenjdk-(\d+)\.jdk$""".r
val From9Pattern = """[^-]+-(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-[^\.]+)?\.jdk$""".r
val From9PatternWithOnlyVersion = """^jdk-(\d+)\.jdk$""".r
type NameAndVersion = (String, VerStr)
def extractVersion(name: String): Option[NameAndVersion] = name match {
case Before9Pattern(major, minor, patch) =>
Some((name, VerStr(major, Option(minor), Option(patch))))
case From9Pattern(major, minor, patch) =>
Some((name, VerStr(major, Option(minor), Option(patch))))
case From9PatternWithOnlyVersion(major) =>
Some((name, VerStr(major, None, None)))
case Before9AdoptOpenJdkPattern(major) =>
Some((name, VerStr(major, None, None)))
case _ =>
None
}
val names = (Process(Seq("bash", "-c", "ls -d */"), Option(javaBaseDir)).lineStream)
.map(line => if (line.endsWith("/")) line.dropRight(1) else line)
.map(extractVersion)
.foldLeft(Vector[NameAndVersion]()) {
case (acc, Some(x@(_, VerStr(v, _, _)))) if v == version =>
acc :+ x
case (acc, _) =>
acc
}
.sortBy(_._2)
def askUserToSelectJdk(names: Vector[NameAndVersion]): Option[NameAndVersion] = {
val listOfJdk = names.zipWithIndex.map { case ((name, split), index) => s"[$index] $name" }
println(s"""
|Version(s) found:
|${listOfJdk.mkString("\n")}
|[c] Cancel
""".stripMargin)
val length = listOfJdk.length
@scala.annotation.tailrec
def getAnswer(choice: String): Option[String] = choice match {
case "c" | "C" => None
case whatever if isPositiveNumber(choice) && choice.toInt < length => Option(choice)
case _ =>
print("Please enter a number on the list: ")
getAnswer(StdIn.readLine())
}
getAnswer("x").map(_.toInt).map(names(_))
}
println(askUserToSelectJdk(names).flatMap {
case (name, ver) =>
println(s"""
|You chose '$name'.
|It will create a symbolic link to '$name' (i.e. jdk${ver.major} -> $name) and may ask you to enter your password.""".stripMargin)
print("Would you like to proceed? (Yes / No) or (Y / N) ")
StdIn.readLine() match {
case "y" | "yes" | "Y" | "Yes" =>
val before = s"""${Process(s"ls -l", Option(javaBaseDir)) !!}""".stripMargin
val lsResultLogger = ProcessLogger(line => println(s"\n$line: It is found so will be removed and recreated."),
line => println(s"\n$line: So it is not found so it will be created."))
val result = s"ls -d $javaBaseDirPath/jdk$version" !(lsResultLogger) match {
case 0 =>
if ((s"find $javaBaseDirPath -type l -iname jdk$version" !!).isEmpty) {
println(s"\n'$javaBaseDirPath/jdk$version' already exists and it's not a symbolic link so nothing will be done.")
1
} else {
println(s"""
|$javaBaseDir $$ sudo rm jdk$version
|$javaBaseDir $$ sudo ln -s $name jdk$version """.stripMargin)
Process(s"sudo rm jdk$version", Option(javaBaseDir)) #&& Process(s"sudo ln -s $name jdk$version", Option(javaBaseDir)) !
}
case _ =>
println(s"""
|$javaBaseDir $$ sudo ln -s $name jdk$version """.stripMargin)
Process(s"sudo ln -s $name jdk$version", Option(javaBaseDir)) !
}
Option(result match {
case 0 =>
s"""
|Done!
|
|# Before
|--------------------------------------
|$before
|======================================
|
|# After
|--------------------------------------
|${Process(s"ls -l", Option(javaBaseDir)) !!}
|======================================
|""".stripMargin
case _ =>
"\nFailed: Creating a symbolic link to JDK has failed.\n"
})
case _ =>
None
}
}
.getOrElse("\nCancelled.\n"))
}
@kevin-lee
Copy link
Author

READ Create Symbolic Link to JDK on Mac OSX.md INSTEAD.

Prerequisite

  • Java
  • Scala
  • Homebrew (Not necessary if Java and Scala are already installed).

Cask (required to install Java using Homebrew.)

brew install caskroom/cask/brew-cask 

Java (It will install the latest version.)

brew cask install java 

Scala

brew install scala 

or to install with source code and docs,

brew install scala --with-src --with-docs 

Usage

Run ln-s-jdk.sh

  • It's good to add an alias to ln-s-jdk.sh

e.g.) In the ~/.bashrc or ~/.zshrc

alias ln-s-jdk='/path/to/script/ln-s-jdk.sh'
  • Then run
$ ln-s-jdk [VERSION NUMBER] 

e.g.)

$ ln-s-jdk 8 

A result might be

Version(s) found:

[0] jdk1.8.0_40.jdk
[1] jdk1.8.0_31.jdk
[2] jdk1.8.0_25.jdk
[c] Cancel

Please enter a number on the list: 0

You chose 'jdk1.8.0_40.jdk'.
It will create a symbolic link to 'jdk1.8.0_40.jdk' (i.e. jdk8 -> jdk1.8.0_40.jdk) and may ask you to enter your password.
Would you like to proceed? (Yes / No) or (Y / N) y

/Library/Java/JavaVirtualMachines/jdk8: It is found so will be removed and recreated.

/Library/Java/JavaVirtualMachines $ sudo rm jdk8 
/Library/Java/JavaVirtualMachines $ sudo ln -s jdk1.8.0_40.jdk jdk8 
Password:

Done!

# Before
--------------------------------------
total 16
drwxr-xr-x  3 root  wheel  102  5 Nov 20:18 jdk1.7.0_71.jdk
drwxr-xr-x  2 root  wheel   68  3 Apr 22:20 jdk1.8.0_25.jdk
drwxr-xr-x  2 root  wheel   68  3 Apr 22:37 jdk1.8.0_31.jdk
drwxr-xr-x  3 root  wheel  102  7 Mar 01:30 jdk1.8.0_40.jdk
lrwxr-xr-x  1 root  wheel   15  3 Apr 18:08 jdk7 -> jdk1.7.0_71.jdk
lrwxr-xr-x  1 root  wheel   15  3 Apr 22:38 jdk8 -> jdk1.8.0_31.jdk

======================================

# After
--------------------------------------
total 16
drwxr-xr-x  3 root  wheel  102  5 Nov 20:18 jdk1.7.0_71.jdk
drwxr-xr-x  2 root  wheel   68  3 Apr 22:20 jdk1.8.0_25.jdk
drwxr-xr-x  2 root  wheel   68  3 Apr 22:37 jdk1.8.0_31.jdk
drwxr-xr-x  3 root  wheel  102  7 Mar 01:30 jdk1.8.0_40.jdk
lrwxr-xr-x  1 root  wheel   15  3 Apr 18:08 jdk7 -> jdk1.7.0_71.jdk
lrwxr-xr-x  1 root  wheel   15  3 Apr 22:44 jdk8 -> jdk1.8.0_40.jdk

======================================

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment