Skip to content

Commit fe55554

Browse files
committed
refactored more bits into Script model
1 parent cb58932 commit fe55554

File tree

3 files changed

+185
-171
lines changed

3 files changed

+185
-171
lines changed

src/main/kotlin/kscript/app/Kscript.kt

Lines changed: 9 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import java.io.BufferedReader
66
import java.io.File
77
import java.io.FileInputStream
88
import java.io.InputStreamReader
9-
import java.lang.IllegalArgumentException
109
import java.net.URL
1110
import java.net.UnknownHostException
1211
import kotlin.system.exitProcess
@@ -114,17 +113,12 @@ fun main(args: Array<String>) {
114113
val scriptResource = docopt.getString("script")
115114
val scriptFile = prepareScript(scriptResource, enableSupportApi = docopt.getBoolean("text"))
116115

116+
val script = Script(scriptFile)
117117

118-
val scriptText = scriptFile.readLines()
119-
120-
// Make sure that dependencies declarations are well formatted
121-
if (scriptText.any { it.startsWith("// DEPS") }) {
122-
error("Dependencies must be declared by using the line prefix //DEPS")
123-
}
124118

125119
// Find all //DEPS directives and concatenate their values
126-
val dependencies = collectDependencies(scriptText)
127-
val customRepos = collectRepos(scriptText)
120+
val dependencies = script.collectDependencies()
121+
val customRepos = script.collectRepos()
128122

129123

130124
// Create temopary dev environment
@@ -137,7 +131,7 @@ fun main(args: Array<String>) {
137131
val classpath = resolveDependencies(dependencies, customRepos, loggingEnabled)
138132

139133
// Extract kotlin arguments
140-
val kotlinOpts = collectRuntimeOptions(scriptText)
134+
val kotlinOpts = script.collectRuntimeOptions()
141135

142136

143137
// Optionally enter interactive mode
@@ -155,7 +149,7 @@ fun main(args: Array<String>) {
155149

156150
// Even if we just need and support the //ENTRY directive in case of kt-class
157151
// files, we extract it here to fail if it was used in kts files.
158-
val entryDirective = findEntryPoint(scriptText)
152+
val entryDirective = script.findEntryPoint()
159153

160154
errorIf(entryDirective != null && scriptFileExt == "kts") {
161155
"@Entry directive is just supported for kt class files"
@@ -179,16 +173,13 @@ fun main(args: Array<String>) {
179173
"Main_${className}"
180174
} else {
181175
// extract package from kt-file
182-
val pckg = scriptText.find { it.startsWith("package ") }
183-
?.split("[ ]+".toRegex())?.get(1)?.run { this + "." }
184-
185-
"""${pckg ?: ""}${entryDirective ?: "${className}Kt"}"""
176+
"""${script.pckg ?: ""}${entryDirective ?: "${className}Kt"}"""
186177
}
187178

188179

189180
// infer KOTLIN_HOME if not set
190-
@Suppress("LocalVariableName")
191181
val KOTLIN_HOME = System.getenv("KOTLIN_HOME") ?: guessKotlinHome()
182+
192183
errorIf(KOTLIN_HOME == null) {
193184
"KOTLIN_HOME is not set and could not be inferred from context"
194185
}
@@ -225,19 +216,6 @@ fun main(args: Array<String>) {
225216
}
226217
""".trimIndent())
227218

228-
// // compile the wrapper
229-
// with(evalBash("kotlinc '${mainKotlin}'", wd = mainKotlin.parentFile)) {
230-
// errorIf(exitCode != 0) { "Compilation of script-wrapper failed:$stderr" }
231-
// }
232-
//
233-
// // update the jar to include main-wrapper
234-
// // requireInPath("jar") // disabled because it's another process invocation
235-
// val jarUpdateCmd = "jar uf '${jarFile.absoluteFile}' ${mainKotlin.nameWithoutExtension}*.class"
236-
// with(evalBash(jarUpdateCmd, wd = mainKotlin.parentFile)) {
237-
// errorIf(exitCode != 0) { "Update of script jar with wrapper class failed\n${stderr}" }
238-
// }
239-
240-
// if(loggingEnabled) System.err.println("Done")
241219
"'${mainKotlin.absolutePath}'"
242220
} else {
243221
""
@@ -251,132 +229,11 @@ fun main(args: Array<String>) {
251229

252230

253231
// print the final command to be run by exec
254-
// val joinedUserArgs = args.drop(1 + args.indexOfFirst { it == scriptResource }).joinToString(" ")
255232
val joinedUserArgs = userArgs.joinToString(" ")
256233

257234
println("kotlin ${kotlinOpts} -classpath ${jarFile}${CP_SEPARATOR_CHAR}${KOTLIN_HOME}${File.separatorChar}lib${File.separatorChar}kotlin-script-runtime.jar${CP_SEPARATOR_CHAR}${classpath} ${execClassName} ${joinedUserArgs} ")
258235
}
259236

260-
data class MavenRepo(val id: String, val url: String)
261-
262-
fun collectRepos(scriptText: List<String>): List<MavenRepo> {
263-
val dependsOnMavenPrefix = "^@file:MavenRepository[(]".toRegex()
264-
// only supported annotation format for now
265-
266-
// @file:MavenRepository("imagej", "http://maven.imagej.net/content/repositories/releases/")
267-
return scriptText
268-
.filter { it.contains(dependsOnMavenPrefix) }
269-
.map { it.replaceFirst(dependsOnMavenPrefix, "").split(")")[0] }
270-
.map { it.split(",").map { it.trim(' ', '"', '(') }.let { MavenRepo(it[0], it[1]) } }
271-
272-
// todo add credential support https://stackoverflow.com/questions/36282168/how-to-add-custom-maven-repository-to-gradle
273-
}
274-
275-
276-
fun isKscriptAnnotation(line: String) =
277-
listOf("DependsOn", "KotlinOpts", "Include", "EntryPoint", "MavenRepository", "DependsOnMaven")
278-
.any { line.contains("^@file:${it}[(]".toRegex()) }
279-
280-
281-
fun collectRuntimeOptions(scriptText: List<String>): String {
282-
val koptsPrefix = "//KOTLIN_OPTS "
283-
284-
var kotlinOpts = scriptText.
285-
filter { it.startsWith(koptsPrefix) }.
286-
map { it.replaceFirst(koptsPrefix, "").trim() }
287-
288-
//support for @file:KotlinOpts see #47
289-
val annotatonPrefix = "^@file:KotlinOpts[(]".toRegex()
290-
kotlinOpts += scriptText
291-
.filter { it.contains(annotatonPrefix) }
292-
.map { it.replaceFirst(annotatonPrefix, "").split(")")[0] }
293-
.map { it.trim(' ', '"') }
294-
295-
296-
// Append $KSCRIPT_KOTLIN_OPTS if defined in the parent environment
297-
System.getenv()["KSCRIPT_KOTLIN_OPTS"]?.run {
298-
kotlinOpts = kotlinOpts + this
299-
}
300-
301-
return kotlinOpts.joinToString(" ")
302-
}
303-
304-
305-
//
306-
// Entry directive
307-
//
308-
309-
310-
private val DEPS_COMMENT_PREFIX = "//DEPS "
311-
private val DEPS_ANNOT_PREFIX = "^@file:DependsOn[(]".toRegex()
312-
private val DEPSMAVEN_ANNOT_PREFIX = "^@file:DependsOnMaven[(]".toRegex()
313-
314-
315-
private fun extractDependencies(line: String) = when {
316-
line.contains(DEPS_ANNOT_PREFIX) -> line
317-
.replaceFirst(DEPS_ANNOT_PREFIX, "")
318-
.split(")")[0].split(",")
319-
.map { it.trim(' ', '"') }
320-
321-
line.contains(DEPSMAVEN_ANNOT_PREFIX) -> line
322-
.replaceFirst(DEPSMAVEN_ANNOT_PREFIX, "")
323-
.split(")")[0].trim(' ', '"').let { listOf(it) }
324-
325-
line.startsWith(DEPS_COMMENT_PREFIX) ->
326-
line.split("[ ;,]+".toRegex()).drop(1).map(String::trim)
327-
328-
else ->
329-
throw IllegalArgumentException("can not extract entry point from non-directive")
330-
}
331-
332-
333-
internal fun isDependDeclare(line: String) =
334-
line.startsWith(DEPS_COMMENT_PREFIX) || line.contains(DEPS_ANNOT_PREFIX) || line.contains(DEPSMAVEN_ANNOT_PREFIX)
335-
336-
337-
fun collectDependencies(scriptText: List<String>): List<String> {
338-
val dependencies = scriptText.filter {
339-
isDependDeclare(it)
340-
}.flatMap {
341-
extractDependencies(it)
342-
}.toMutableList()
343-
344-
345-
// if annotations are used add dependency on kscript-annotations
346-
if (scriptText.any { isKscriptAnnotation(it) }) {
347-
dependencies += "com.github.holgerbrandl:kscript-annotations:1.1"
348-
}
349-
350-
return dependencies.distinct()
351-
}
352-
353-
354-
//
355-
// Entry directive
356-
//
357-
358-
private val ENTRY_ANNOT_PREFIX = "^@file:EntryPoint[(]".toRegex()
359-
private const val ENTRY_COMMENT_PREFIX = "//ENTRY "
360-
361-
362-
internal fun isEntryPointDirective(line: String) =
363-
line.startsWith(ENTRY_COMMENT_PREFIX) || line.contains(ENTRY_ANNOT_PREFIX)
364-
365-
366-
internal fun findEntryPoint(scriptText: List<String>): String? {
367-
return scriptText.find { isEntryPointDirective(it) }?.let { extractEntryPoint(it) }
368-
}
369-
370-
private fun extractEntryPoint(line: String) = when {
371-
line.contains(ENTRY_ANNOT_PREFIX) ->
372-
line
373-
.replaceFirst(ENTRY_ANNOT_PREFIX, "")
374-
.split(")")[0].trim(' ', '"')
375-
line.startsWith(ENTRY_COMMENT_PREFIX) ->
376-
line.split("[ ]+".toRegex()).last()
377-
else ->
378-
throw IllegalArgumentException("can not extract entry point from non-directive")
379-
}
380237

381238

382239
/** Determine the latest version by checking github repo and print info if newer version is available. */
@@ -402,6 +259,7 @@ private fun versionCheck() {
402259
}
403260
}
404261

262+
405263
fun prepareScript(scriptResource: String, enableSupportApi: Boolean): File {
406264
var scriptFile: File?
407265

@@ -451,8 +309,6 @@ fun prepareScript(scriptResource: String, enableSupportApi: Boolean): File {
451309
"Could not read script argument '$scriptResource'"
452310
}
453311

454-
val extension = scriptFile!!.extension
455-
456312
// note script file must be not null at this point
457313

458314
// include preamble for custom interpreters (see https://github.com/holgerbrandl/kscript/issues/67)
@@ -476,7 +332,7 @@ fun prepareScript(scriptResource: String, enableSupportApi: Boolean): File {
476332
// System.err.println("[kscript] temp script file is ${scriptFile}")
477333
// System.err.println("[kscript] temp script file is \n${Script(scriptFile!!)}")
478334

479-
// support //INCLUDE directive (see https://github.com/holgerbrandl/kscript/issues/34)
335+
// resolve all includes (see https://github.com/holgerbrandl/kscript/issues/34)
480336
scriptFile = resolveIncludes(scriptFile!!)
481337

482338
return scriptFile!!

0 commit comments

Comments
 (0)