/
Coursier.scala
166 lines (141 loc) · 5.71 KB
/
Coursier.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package coursier.cli
import java.io.InputStream
import java.nio.charset.StandardCharsets
import java.util.Scanner
import caseapp.core.RemainingArgs
import caseapp.core.help.Help
import caseapp.core.parser.Parser
import coursier.cache.CacheUrl
import coursier.cli.bootstrap.Bootstrap
import coursier.cli.channel.Channel
import coursier.cli.complete.Complete
import coursier.cli.fetch.Fetch
import coursier.cli.get.Get
import coursier.cli.install.{Install, List, Uninstall, Update}
import coursier.cli.jvm.{Java, JavaHome}
import coursier.cli.launch.Launch
import coursier.cli.publish.Publish
import coursier.cli.resolve.Resolve
import coursier.cli.setup.{Setup, SetupOptions}
import coursier.cli.search.Search
import coursier.core.Version
import coursier.install.InstallDir
import coursier.launcher.internal.{FileUtil, Windows}
import shapeless._
import scala.util.control.NonFatal
object Coursier extends CommandAppPreA(Parser[LauncherOptions], Help[LauncherOptions], CoursierCommand.parser, CoursierCommand.help) {
val isGraalvmNativeImage = sys.props.contains("org.graalvm.nativeimage.imagecode")
if (System.console() != null && Windows.isWindows) {
val useJni = coursier.paths.Util.useJni()
try {
if (useJni)
coursier.jniutils.WindowsAnsiTerminal.enableAnsiOutput()
else
io.github.alexarchambault.windowsansi.WindowsAnsi.setup()
} catch {
case NonFatal(e) =>
val doThrow = java.lang.Boolean.getBoolean("coursier.windows-ansi.throw-exception")
if (doThrow || java.lang.Boolean.getBoolean("coursier.windows-ansi.verbose"))
System.err.println(s"Error setting up Windows terminal for ANSI escape codes: $e")
if (doThrow)
throw e
}
}
CacheUrl.setupProxyAuth()
override val appName = "Coursier"
override val progName =
if (isGraalvmNativeImage) "cs"
else "coursier"
override val appVersion = coursier.util.Properties.version
private def zshCompletions(): String = {
var is: InputStream = null
val b = try {
is = Thread.currentThread()
.getContextClassLoader
.getResource("completions/zsh")
.openStream()
FileUtil.readFully(is)
} finally {
if (is != null)
is.close()
}
new String(b, StandardCharsets.UTF_8)
}
private def runSetup(): Unit = {
Setup.run(SetupOptions(banner = Some(true)), RemainingArgs(Nil, Nil))
// https://stackoverflow.com/questions/26184409/java-console-prompt-for-enter-input-before-moving-on/26184535#26184535
println("Press \"ENTER\" to continue...")
val scanner = new Scanner(System.in)
scanner.nextLine()
}
private def isInstalledLauncher: Boolean =
System.getenv(InstallDir.isInstalledLauncherEnvVar) == "true"
override def main(args: Array[String]): Unit = {
val csArgs =
if (isGraalvmNativeImage) {
// process -J* args ourselves
val (jvmArgs, csArgs0) = args.partition(_.startsWith("-J"))
for (jvmArg <- jvmArgs) {
val arg = jvmArg.stripPrefix("-J")
if (arg.startsWith("-D"))
arg.stripPrefix("-D").split("=", 2) match {
case Array(k) => System.setProperty(k, "")
case Array(k, v) => System.setProperty(k, v)
}
else
System.err.println(s"Warning: ignoring unhandled -J argument: $jvmArg")
}
csArgs0
} else
args
if (csArgs.nonEmpty)
super.main(csArgs)
else if (Windows.isWindows && !isInstalledLauncher)
runSetup()
else
helpAsked()
}
def beforeCommand(options: LauncherOptions, remainingArgs: Seq[String]): Unit = {
if(options.version) {
System.out.println(appVersion)
sys.exit(0)
}
for (requiredVersion <- options.require.map(_.trim).filter(_.nonEmpty)) {
val requiredVersion0 = Version(requiredVersion)
val currentVersion = coursier.util.Properties.version
val currentVersion0 = Version(currentVersion)
if (currentVersion0.compare(requiredVersion0) < 0) {
System.err.println(s"Required version $requiredVersion > $currentVersion")
sys.exit(1)
}
}
options.completions.foreach {
case "zsh" =>
System.out.print(zshCompletions())
sys.exit(0)
case other =>
System.err.println(s"Unrecognized or unsupported shell: $other")
sys.exit(1)
}
}
object runWithOptions extends Poly1 {
private def opt[T](run: (T, RemainingArgs) => Unit) = at[T](run.curried)
implicit val atBootstrap = opt[bootstrap.BootstrapOptions] (Bootstrap.run)
implicit val atChannel = opt[channel.ChannelOptions] (Channel.run)
implicit val atComplete = opt[complete.CompleteOptions] (Complete.run)
implicit val atFetch = opt[fetch.FetchOptions] (Fetch.run)
implicit val atGet = opt[get.GetOptions] (Get.run)
implicit val atInstall = opt[install.InstallOptions] (Install.run)
implicit val atJava = opt[jvm.JavaOptions] (Java.run)
implicit val atJavaHome = opt[jvm.JavaHomeOptions] (JavaHome.run)
implicit val atLaunch = opt[launch.LaunchOptions] (Launch.run)
implicit val atList = opt[install.ListOptions] (List.run)
implicit val atPublish = opt[publish.options.PublishOptions](Publish.run)
implicit val atResolve = opt[resolve.ResolveOptions] (Resolve.run)
implicit val atSearch = opt[search.SearchOptions] (Search.run)
implicit val atSetup = opt[setup.SetupOptions] (Setup.run)
implicit val atUninstall = opt[install.UninstallOptions] (Uninstall.run)
implicit val atUpdate = opt[install.UpdateOptions] (Update.run)
}
def runA = _.fold(runWithOptions)
}