This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 2e9f11ed57 GROOVY-11742: posix commands should support variable
assignment (amendments for /cat and /head)
2e9f11ed57 is described below
commit 2e9f11ed5751c0ef47bdfdaca8e315b9280a9afc
Author: Paul King <[email protected]>
AuthorDate: Mon Aug 25 13:22:51 2025 +1000
GROOVY-11742: posix commands should support variable assignment (amendments
for /cat and /head)
---
.../groovy/org/apache/groovy/groovysh/Main.groovy | 13 +-
.../groovy/groovysh/jline/GroovyPosixCommands.java | 137 +++++++++++++++------
2 files changed, 110 insertions(+), 40 deletions(-)
diff --git
a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Main.groovy
b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Main.groovy
index d9865599fe..3d07e07472 100644
---
a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Main.groovy
+++
b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Main.groovy
@@ -82,7 +82,7 @@ import static org.jline.jansi.AnsiRenderer.render
class Main {
private static final MessageSource messages = new MessageSource(Main)
public static final String INTERPRETER_MODE_PREFERENCE_KEY =
'interpreterMode'
- private static POSIX_FILE_CMDS = ['/tail', '/head', '/wc', '/sort']
+ private static POSIX_FILE_CMDS = ['/tail', '/wc', '/sort']
@SuppressWarnings("resource")
protected static class ExtraConsoleCommands extends JlineCommandRegistry
implements CommandRegistry {
@@ -113,6 +113,7 @@ class Main {
'/echo' : new CommandMethods((Function) this::echo,
this::defaultCompleter),
'/ls' : new CommandMethods((Function) this::ls,
this::optFileCompleter),
'/grep' : new CommandMethods((Function) this::grepcmd,
this::optFileCompleter),
+ '/head' : new CommandMethods((Function) this::headcmd,
this::optFileCompleter),
'/cat' : new CommandMethods((Function) this::cat,
this::optFileCompleter),
"/!" : new CommandMethods((Function) this::shell,
this::defaultCompleter)
]
@@ -190,6 +191,14 @@ class Main {
}
}
+ private void headcmd(CommandInput input) {
+ try {
+ GroovyPosixCommands.head(context(input), ['/head',
*input.xargs()] as Object[])
+ } catch (Exception e) {
+ saveException(e)
+ }
+ }
+
private GroovyPosixContext context(CommandInput input) {
GroovyPosixContext ctx = new GroovyPosixContext(input.in(),
input.out(), input.err(),
posix.context.currentDir(), input.terminal(),
scriptEngine::get)
@@ -198,7 +207,7 @@ class Main {
private void cat(CommandInput input) {
try {
- GroovyPosixCommands.cat(context(input), ['/cat',
*input.args()] as String[])
+ GroovyPosixCommands.cat(context(input), ['/cat',
*input.xargs()] as Object[])
} catch (Exception e) {
saveException(e)
}
diff --git
a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyPosixCommands.java
b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyPosixCommands.java
index 3686e2cd9c..5cde0fcc24 100644
---
a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyPosixCommands.java
+++
b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyPosixCommands.java
@@ -76,10 +76,10 @@ import java.util.stream.Stream;
// https://github.com/jline/jline3/pull/1390
public class GroovyPosixCommands extends PosixCommands {
- public static void cat(Context context, String[] argv) throws Exception {
+ public static void cat(Context context, Object[] argv) throws Exception {
final String[] usage = {
- "/cat - concatenate and print FILES",
- "Usage: /cat [OPTIONS] [FILES]",
+ "/cat - concatenate and print FILES or VARIABLES",
+ "Usage: /cat [OPTIONS] [FILES] [VARIABLES]",
" -? --help show help",
" -n number the output lines, starting at 1"
};
@@ -89,28 +89,14 @@ public class GroovyPosixCommands extends PosixCommands {
if (args.isEmpty()) {
args = Collections.singletonList("-");
}
- List<InputStream> expanded = new ArrayList<>();
- for (String arg : args) {
- if ("-".equals(arg)) {
- expanded.add(context.in());
- } else {
- expanded.addAll(maybeExpandGlob(context, arg).stream()
- .map(p -> {
- try {
- return p.toUri().toURL().openStream();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- })
- .collect(Collectors.toList()));
- }
- }
- for (InputStream is : expanded) {
- cat(context, new BufferedReader(new InputStreamReader(is)),
opt.isSet("n"));
+ List<NamedInputStream> sources = getSources(context, argv, args);
+ for (NamedInputStream nis : sources) {
+ InputStream is = nis.getInputStream();
+ doCat(context, new BufferedReader(new InputStreamReader(is)),
opt.isSet("n"));
}
}
- private static void cat(Context context, BufferedReader reader, boolean
numbered) throws IOException {
+ private static void doCat(Context context, BufferedReader reader, boolean
numbered) throws IOException {
String line;
int lineno = 1;
try {
@@ -126,6 +112,75 @@ public class GroovyPosixCommands extends PosixCommands {
}
}
+ public static void head(Context context, Object[] argv) throws Exception {
+ final String[] usage = {
+ "/head - display first lines of files or variables",
+ "Usage: /head [-n lines | -c bytes] [file|variable ...]",
+ " -? --help Show help",
+ " -n --lines=LINES Print line counts",
+ " -c --bytes=BYTES Print byte counts",
+ };
+ Options opt = parseOptions(context, usage, argv);
+
+ if (opt.isSet("lines") && opt.isSet("bytes")) {
+ throw new IllegalArgumentException("usage: head [-n # | -c #]
[file ...]");
+ }
+
+ int nbLines = Integer.MAX_VALUE;
+ int nbBytes = Integer.MAX_VALUE;
+ if (opt.isSet("lines")) {
+ nbLines = opt.getNumber("lines");
+ } else if (opt.isSet("bytes")) {
+ nbBytes = opt.getNumber("bytes");
+ } else {
+ nbLines = 10; // default
+ }
+
+ List<String> args = opt.args();
+ if (args.isEmpty()) {
+ args = Collections.singletonList("-");
+ }
+
+ boolean first = true;
+ List<NamedInputStream> sources = getSources(context, argv, args);
+ for (NamedInputStream nis : sources) {
+ if (!first && args.size() > 1) {
+ context.out().println();
+ }
+ if (args.size() > 1) {
+ context.out().println("==> " + nis.getName() + " <==");
+ }
+
+ InputStream is = nis.getInputStream();
+ if (nbLines != Integer.MAX_VALUE) {
+ try (BufferedReader reader = new BufferedReader(new
InputStreamReader(is))) {
+ String line;
+ int count = 0;
+ while ((line = reader.readLine()) != null && count <
nbLines) {
+ context.out().println(line);
+ count++;
+ }
+ }
+ } else {
+ byte[] buffer = new byte[nbBytes];
+ int bytesRead = is.read(buffer);
+ if (bytesRead > 0) {
+ context.out().write(buffer, 0, bytesRead);
+ }
+ is.close();
+ }
+ first = false;
+ }
+ }
+
+ private static InputStream newInputStream(Path p) {
+ try {
+ return Files.newInputStream(p);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
public static void ls(Context context, String[] argv) throws Exception {
final String[] usage = {
"/ls - list files",
@@ -583,18 +638,7 @@ public class GroovyPosixCommands extends PosixCommands {
if (args.isEmpty()) {
args.add("-");
}
- List<GrepSource> sources = new ArrayList<>();
- for (String arg : args) {
- if ("-".equals(arg)) {
- sources.add(new GrepSource(context.in(), "(standard input)"));
- } else if (arg.startsWith("[Ljava.lang.String;@")) {
- sources.add(new GrepSource(variableInputStream(argv, arg),
arg));
- } else {
- sources.addAll(maybeExpandGlob(context, arg).stream()
- .map(gp -> new GrepSource(gp, gp.toString()))
- .collect(Collectors.toList()));
- }
- }
+ List<NamedInputStream> sources = getSources(context, argv, args);
boolean filenameHeader = sources.size() > 1;
if (opt.isSet("header")) {
filenameHeader = true;
@@ -602,7 +646,7 @@ public class GroovyPosixCommands extends PosixCommands {
filenameHeader = false;
}
boolean match = false;
- for (GrepSource src : sources) {
+ for (NamedInputStream src : sources) {
List<String> lines = new ArrayList<>();
boolean firstPrint = true;
int nb = 0;
@@ -763,6 +807,22 @@ public class GroovyPosixCommands extends PosixCommands {
}
}
+ private static List<NamedInputStream> getSources(Context context, Object[]
argv, List<String> args) {
+ List<NamedInputStream> sources = new ArrayList<>();
+ for (String arg : args) {
+ if ("-".equals(arg)) {
+ sources.add(new NamedInputStream(context.in(), "(standard
input)"));
+ } else if (arg.startsWith("[Ljava.lang.String;@")) {
+ sources.add(new NamedInputStream(variableInputStream(argv,
arg), arg));
+ } else {
+ sources.addAll(maybeExpandGlob(context, arg).stream()
+ .map(gp -> new NamedInputStream(newInputStream(gp),
gp.toString()))
+ .collect(Collectors.toList()));
+ }
+ }
+ return sources;
+ }
+
private static ByteArrayInputStream variableInputStream(Object[] argv,
String arg) {
String[] found = (String[]) Arrays.stream(argv).filter(v ->
v.toString().equals(arg)).findFirst().get();
ByteArrayInputStream inputStream = new
ByteArrayInputStream(ArrayGroovyMethods.join(found,
"\n").getBytes(StandardCharsets.UTF_8));
@@ -808,18 +868,19 @@ public class GroovyPosixCommands extends PosixCommands {
Less less = new Less(context.terminal(), context.currentDir(), opt);
less.run(sources);
}
- private static class GrepSource {
+
+ private static class NamedInputStream {
private final InputStream inputStream;
private final Path path;
private final String name;
- public GrepSource(InputStream inputStream, String name) {
+ public NamedInputStream(InputStream inputStream, String name) {
this.inputStream = inputStream;
this.path = null;
this.name = name;
}
- public GrepSource(Path path, String name) {
+ public NamedInputStream(Path path, String name) {
this.inputStream = null;
this.path = path;
this.name = name;