Skip to content

Commit cfe5dca

Browse files
committed
GROOVY-11791: Support unquoted URLs in groovysh
1 parent a20c827 commit cfe5dca

File tree

4 files changed

+22
-14
lines changed

4 files changed

+22
-14
lines changed

subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Main.groovy

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,8 +471,9 @@ class Main {
471471
line = line.readLines().collect{ s ->
472472
// remove Groovy continuation character for repl not Groovy's sake
473473
s.endsWith(' \\') ? s[0..-3] : s
474-
}.join('\n')
474+
}.join('\n').replaceAll($/(/[a-z]+\s+)(https?://\S+)/$, '$1"$2"') // quote URLs after commands
475475
if (line.startsWith(':')) {
476+
// some simple legacy support for ':' commands
476477
def maybeCmd = line.split()[0].replaceFirst(':', '/')
477478
if (systemRegistry.hasCommand(maybeCmd) || systemRegistry.isCommandAlias(maybeCmd)) {
478479
line = line.replaceFirst(':', '/')

subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyCommands.groovy

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,9 @@ class GroovyCommands extends JlineCommandRegistry implements CommandRegistry {
376376
try {
377377
path = workDir.get().resolve(arg)
378378
} catch(Exception ignore) { }
379+
Reader source = null
379380
if (path && Files.exists(path)) {
381+
source = Files.newBufferedReader(path, encoding)
380382
if (!format) {
381383
def ext = path.extension
382384
if (ext.equalsIgnoreCase('json')) {
@@ -397,23 +399,26 @@ class GroovyCommands extends JlineCommandRegistry implements CommandRegistry {
397399
format = 'TEXT'
398400
}
399401
}
402+
}
403+
if (!source && (arg.startsWith('http://') || arg.startsWith('https://'))) {
404+
URL url = new URL(arg)
405+
source = new InputStreamReader(url.openStream(), encoding)
406+
}
407+
if (source) {
400408
if (format == 'TEXT') {
401-
out = Files.readAllLines(path, encoding)
409+
out = source.readLines()
402410
} else if (format in engine.deserializationFormats) {
403-
byte[] encoded = Files.readAllBytes(path)
404-
out = engine.deserialize(new String(encoded, encoding), format)
411+
out = engine.deserialize(source.text, format)
405412
} else if (format in slurpers.keySet()) {
406413
def parser = getParser(format, slurpers[format])
407-
out = parser.parse(path)
414+
out = parser.parse(source)
408415
} else if (format == 'CSV') {
409416
def parser = getCsvParser(format)
410-
out = parser.parse(path.newReader(encoding.displayName())).toList()*.toMap()
417+
out = parser.parse(source).toList()*.toMap()
411418
} else if (format == 'PROPERTIES') {
412-
out = path.withInputStream{ is ->
413-
new Properties().tap {load(is) }
414-
}
419+
out = new Properties().tap {load(source) }
415420
} else {
416-
out = engine.deserialize(Files.readString(path, encoding), 'NONE')
421+
out = engine.deserialize(source.text, 'AUTO')
417422
}
418423
} else {
419424
if (format == 'TEXT') {
@@ -427,7 +432,7 @@ class GroovyCommands extends JlineCommandRegistry implements CommandRegistry {
427432
def parser = getCsvParser(format)
428433
out = parser.parse(new StringReader(arg)).toList()*.toMap()
429434
} else {
430-
out = engine.deserialize(arg, 'NONE')
435+
out = engine.deserialize(arg, 'AUTO')
431436
}
432437
}
433438
} catch (Exception ignore) {

subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyEngine.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ public class GroovyEngine implements ScriptEngine {
9090
public enum Format {
9191
JSON,
9292
GROOVY,
93-
NONE
93+
NONE,
94+
AUTO
9495
}
9596

9697
public static final String CANONICAL_NAMES = "canonicalNames";

subprojects/groovy-groovysh/src/main/resources/nanorc/groovy.nanorc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ TYPE: "\<(boolean|byte|char|def|double|float|int|it|long|new|short|this|t
1919
KEYWORD: "\<(case|catch|default|do|else|finally|for|if|return|switch|throw|try|while)\>"
2020
KEYWORD: "\<(abstract|class|extends|final|implements|import|instanceof|interface|native|non-sealed|package)\>"
2121
KEYWORD: "\<(permits|private|protected|public|record|sealed|static|strictfp|super|synchronized|throws|trait|volatile)\>"
22-
PACKAGE: "(([a-z0-9]{2,}[.]{1}){2,10}([a-z0-9]{2,}){0,1})"
22+
PATH: "\<https?://\S*\>"
23+
PACKAGE: "(?<!://\w{0,99})(([a-z0-9]{2,}[.]{1}){2,10}([a-z0-9]{2,}){0,1})"
2324

2425
CLASS: "\<[A-Z]{0,2}([A-Z]{1}[a-z0-9]+){1,}\>"
2526
# Annotation
@@ -37,7 +38,7 @@ OPERATOR: "[-+/*=<>?:!~%&|]"
3738
~NUMBER: "\b-?(([1-9][0-9_]*)|0)\.[0-9_e]+[dfg]?\b" "\b-?([1-9][0-9_]*)?[0-9][ilg]?\b" "\b0[0-7_]*[ilg]?\b" "\b0x([1-9a-f][0-9a-f_]*)?[0-9a-f][lg]?\b" "\b0b([01][01_]*)?[01]\b"
3839
#STRING: "['][^']*[^\\][']" "[']{3}.*[^\\][']{3}"
3940
$BALANCED_DELIMITERS: """", ''', ', ""
40-
$LINE_COMMENT: "//"
41+
$LINE_COMMENT: "(?<!:)//"
4142
$BLOCK_COMMENT: "/*, */"
4243
REGEXP: "~/[^/]*/"
4344

0 commit comments

Comments
 (0)