@@ -6,7 +6,6 @@ import java.io.BufferedReader
66import java.io.File
77import java.io.FileInputStream
88import java.io.InputStreamReader
9- import java.lang.IllegalArgumentException
109import java.net.URL
1110import java.net.UnknownHostException
1211import 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+
405263fun 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