-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsdkmantool.js
173 lines (148 loc) · 5.57 KB
/
sdkmantool.js
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
167
168
169
170
171
172
173
import fs from "fs"
import path from "path"
import assert from "assert"
import process from "process"
import fsPromises from "fs/promises"
import Tool from "./tool.js"
// abstract class
export default class SdkmanTool extends Tool {
static tool = "sdkman"
static envVar = "SDKMAN_DIR"
static installer = "sdk"
static installerPath = ".sdkman"
static installerVersion = "sdk version"
constructor(extendingTool) {
super(extendingTool)
}
/**
* Return the path to the tool installation directory, if found, otherwise
* return the default path to the tool.
*
* @returns {String} - Path to the root folder of the tool.
*/
async findRoot() {
;(function () {
// Shortcut this
if (this.sdkShimChecked) return
// All of this is to check if we have a sdkman install that hasn't
// been shimmed which won't be found correctly
let check = this.defaultRoot
this.debug(`checking with defaultRoot: ${check}`)
if (!fs.existsSync(check)) return
this.debug("defaultRoot exists")
check = path.join(check, "bin", "sdkman-init.sh")
if (!fs.existsSync(check)) return
this.debug("sdkman-init.sh exists")
check = path.join(this.defaultRoot, "bin", "sdk")
if (fs.existsSync(check)) {
this.debug(`sdk shim found at: ${check}`)
this.sdkShimChecked = true
return
}
this.debug("sdk shim does not exist")
this.shimSdk(this.defaultRoot)
}).bind(this)()
return super.findRoot()
}
/**
* Download and configures sdkman.
*
* @param {string} root - Directory to install sdkman into (SDKMAN_DIR).
* @param {string} noShim - Don't install the `sdk` shim.
* @return {string} The value of SDKMAN_DIR.
*/
async install(root, noShim = false) {
assert(root, "root is required")
const url = "https://get.sdkman.io?rcupdate=false"
const install = await this.downloadTool(url)
// Export the SDKMAN_DIR for installation location
await this.setEnv(root)
// Create an env copy so we don't call findRoot during the install
const env = { ...process.env, ...(await this.getEnv(root)) }
// Remove the root dir, because Sdkman will not install if it exists,
// which is dumb, but that's what we got
if (fs.existsSync(root)) await fsPromises.rmdir(root)
// Run the installer script
await this.subprocessShell(`bash ${install}`, { env: env })
// Shim the sdk cli function and add to the path
if (!noShim) this.shimSdk(root)
// Asynchronously clean up the downloaded installer script
fsPromises.rm(install, { recursive: true }).catch(() => {})
return root
}
/**
* Create a shim for the `sdk` CLI functions that otherwise would require an
* active shell.
*
* @param {string} root - The root directory of the sdkman installation.
*/
shimSdk(root) {
const shim = path.join(root, "bin", "sdk")
// This is our actual sdk shim script
const shimTmpl = `\
#!/bin/bash
export SDKMAN_DIR="${root}"
SDKMAN_INIT_FILE="$SDKMAN_DIR/bin/sdkman-init.sh"
if [[ ! -s "$SDKMAN_INIT_FILE" ]]; then exit 13; fi
if [[ -z "$SDKMAN_AVAILABLE" ]]; then source "$SDKMAN_INIT_FILE" >/dev/null; fi
export -f
sdk "$@"
`
this.info(`Creating sdk shim at ${shim}`)
// Ensure we have a path to install the shim to, no matter what
fs.mkdirSync(path.dirname(shim), { recursive: true })
// Remove the shim if there's something there, it's probably bad
if (fs.existsSync(shim)) fs.rmSync(shim)
// Write our new shim
fs.writeFileSync(shim, shimTmpl, { mode: 0o755 })
}
/**
* Ensure that the sdkman config file contains the settings necessary for
* executing in a non-interactive CI environment.
*/
checkSdkmanSettings(configFile) {
// Easy case, no file, make sure the directory exists and write config
if (!fs.existsSync(configFile)) {
this.debug("writing sdkman config")
const configPath = path.dirname(configFile)
fs.mkdirSync(configPath, { recursive: true })
// This config is taken from the packer repo
fs.writeFileSync(
configFile,
`\
sdkman_auto_answer=true
sdkman_auto_complete=true
sdkman_auto_env=true
sdkman_beta_channel=false
sdkman_colour_enable=true
sdkman_curl_connect_timeout=7
sdkman_curl_max_time=10
sdkman_debug_mode=false
sdkman_insecure_ssl=false
sdkman_rosetta2_compatible=false
sdkman_selfupdate_enable=false`,
)
return
}
this.debug("sdkman config already present")
// If we get here, the file exists, and we just hope it's configured right
let data = fs.readFileSync(configFile, "utf8")
if (/sdkman_auto_answer=true/.test(data)) {
// We're good
this.debug("sdkman config okay")
return
}
this.debug("sdkman config misconfigured, maybe")
this.debug(fs.readFileSync(configFile, "utf8"))
this.debug("overwriting it because otherwise this tool won't work")
data = data.replace(
/sdkman_auto_answer=false/,
"sdkman_auto_answer=true",
)
data = data.replace(
/sdkman_selfupdate_enable=true/,
"sdkman_selfupdate_enable=true",
)
fs.writeFileSync(configFile, data)
}
}