Skip to content

Commit 716c402

Browse files
committed
Fixed last broken case (I can not confirm idea and packaging tests)
1 parent f92c9e6 commit 716c402

File tree

2 files changed

+33
-23
lines changed

2 files changed

+33
-23
lines changed

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

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ fun main(args: Array<String>) {
108108
// Resolve the script resource argument into an actual file
109109
val scriptResource = docopt.getString("script")
110110

111-
val rawUri = prepareScript(scriptResource)
111+
val (rawUri, includeContext) = prepareScript(scriptResource)
112112

113113
if (docopt.getBoolean("add-bootstrap-header")) {
114114
errorIf(!isFile(rawUri)) {
@@ -150,7 +150,7 @@ fun main(args: Array<String>) {
150150

151151
// post process script (text-processing mode, custom dsl preamble, resolve includes)
152152
// and finally resolve all includes (see https://github.com/holgerbrandl/kscript/issues/34)
153-
val (scriptFile, includeURLs) = resolveIncludes(resolvePreambles(rawUri, enableSupportApi))
153+
val (scriptFile, includeURLs) = resolveIncludes(resolvePreambles(rawUri, enableSupportApi), includeContext)
154154

155155
val script = Script(scriptFile)
156156

@@ -328,58 +328,69 @@ private fun versionCheck() {
328328
}
329329
}
330330

331+
fun prepareScript(scriptResource: String): Pair<URI, URI> {
332+
var scriptFile: File?
331333

332-
fun prepareScript(scriptResource: String): URI {
333-
if (isUrl(scriptResource)) {
334-
return URI(scriptResource)
335-
}
336-
337-
var scriptUri: URI?
334+
// we need to keep track of the scripts dir or the working dir in case of stdin script to correctly resolve includes
335+
var includeContext: URI = File(".").toURI()
338336

339337
// map script argument to script file
340-
scriptUri = with(File(scriptResource)) {
338+
scriptFile = with(File(scriptResource)) {
341339
if (!canRead()) {
342340
// not a file so let's keep the script-file undefined here
343341
null
344342
} else if (listOf("kts", "kt").contains(extension)) {
345-
this.toURI()
343+
// update include context
344+
includeContext = this.absoluteFile.parentFile.toURI()
345+
346+
// script input is a regular script or clas file
347+
this
346348
} else {
347349
// if we can "just" read from script resource create tmp file
348350
// i.e. script input is process substitution file handle
349351
// not FileInputStream(this).bufferedReader().use{ readText()} does not work nor does this.readText
350-
createTmpScript(FileInputStream(this).bufferedReader().readText()).toURI()
352+
includeContext = this.absoluteFile.parentFile.toURI()
353+
createTmpScript(FileInputStream(this).bufferedReader().readText())
351354
}
352355
}
353356

354357
// support stdin
355358
if (scriptResource == "-" || scriptResource == "/dev/stdin") {
356359
val scriptText = generateSequence() { readLine() }.joinToString("\n").trim()
357-
scriptUri = createTmpScript(scriptText).toURI()
360+
scriptFile = createTmpScript(scriptText)
358361
}
359362

363+
364+
// Support URLs as script files
365+
if (scriptResource.startsWith("http://") || scriptResource.startsWith("https://")) {
366+
scriptFile = fetchFromURL(scriptResource)
367+
368+
includeContext = URI(scriptResource.run { substring(lastIndexOf('/') + 1) })
369+
}
370+
371+
360372
// Support for support process substitution and direct script arguments
361-
if (scriptUri == null && !scriptResource.endsWith(".kts") && !scriptResource.endsWith(".kt")) {
373+
if (scriptFile == null && !scriptResource.endsWith(".kts") && !scriptResource.endsWith(".kt")) {
362374
val scriptText = if (File(scriptResource).canRead()) {
363375
File(scriptResource).readText().trim()
364376
} else {
365377
// the last resort is to assume the input to be a kotlin program
366378
scriptResource.trim()
367379
}
368380

369-
scriptUri = createTmpScript(scriptText).toURI()
381+
scriptFile = createTmpScript(scriptText)
370382
}
371383

372384
// just proceed if the script file is a regular file at this point
373-
errorIf(scriptUri == null) {
385+
errorIf(scriptFile == null || !scriptFile.canRead()) {
374386
"Could not read script argument '$scriptResource'"
375387
}
376388

377389
// note script file must be not null at this point
378390

379-
return scriptUri!!
391+
return Pair(scriptFile!!.toURI(), includeContext)
380392
}
381393

382-
383394
private fun resolvePreambles(rawUri: URI, enableSupportApi: Boolean): URI {
384395
if (!isFile(rawUri)) {
385396
return rawUri

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const val IMPORT_STATEMENT_PREFIX = "import " // todo make more solid by using o
1616
data class IncludeResult(val scriptFile: File, val includes: List<URL> = emptyList())
1717

1818
/** Resolve include declarations in a script file. Resolved script will be put into another temporary script */
19-
fun resolveIncludes(uri: URI): IncludeResult {
19+
fun resolveIncludes(uri: URI, includeContext: URI = uri.resolve(".")): IncludeResult {
2020
val scriptText = uri.toURL().readText()
2121

2222
val urlExtension = when {
@@ -30,21 +30,20 @@ fun resolveIncludes(uri: URI): IncludeResult {
3030
}
3131

3232
val includes = mutableListOf<URI>()
33-
val lines = resolve(isFile(uri), uri, includes)
33+
val lines = resolve(isFile(uri), uri, includeContext, includes)
3434
val script = Script(lines, urlExtension)
3535

3636
return IncludeResult(script.consolidateStructure().createTmpScript(), includes.map { it.toURL() })
3737
}
3838

39-
private fun resolve(allowFileReferences: Boolean, scriptUri: URI, includes: MutableList<URI>): List<String> {
39+
private fun resolve(allowFileReferences: Boolean, scriptUri: URI, includeContext: URI, includes: MutableList<URI>): List<String> {
4040
val lines = readLines(scriptUri)
41-
val scriptPath = scriptUri.resolve(".")
4241
val result = mutableListOf<String>()
4342

4443
for (line in lines) {
4544
if (isIncludeDirective(line)) {
4645
val include = extractTarget(line)
47-
val includeUri = resolveUri(scriptPath, include)
46+
val includeUri = resolveUri(includeContext, include)
4847

4948
if (!allowFileReferences && isFile(includeUri)) {
5049
errorMsg("References to local filesystem from remote scripts are not allowed.\nIn script: $scriptUri; Reference: $includeUri")
@@ -59,7 +58,7 @@ private fun resolve(allowFileReferences: Boolean, scriptUri: URI, includes: Muta
5958

6059
includes.add(includeUri)
6160

62-
val resolvedLines = resolve(allowFileReferences && isFile(includeUri), includeUri, includes)
61+
val resolvedLines = resolve(allowFileReferences && isFile(includeUri), includeUri, includeUri.resolve("."), includes)
6362
result.addAll(resolvedLines)
6463
continue
6564
}

0 commit comments

Comments
 (0)