4

I'm trying to use Apache Commons Exec to run a git command which uses a regex.

When I form my CommandLine and print it out it looks like this:

[git, --no-pager, grep, --line-number, --untracked, --extended-regexp, "^\s*public void\s+(testFindByAdAccount).*", --, *Test.java]

However when I execute this, git returns no results, resulting in an exit code 1.

When I run this command manually though, it returns plenty of results and succeeds. Changing the --extended-regexp argument to just a string like testFindByAdAccount does yield results when run via Exec, so I think Apache Commons is doing something to the regexp argument making it invalid. Any ideas what is going on?

EDIT: Adding a reproducible example

  1. Clone https://github.com/ragurney/min-example
  2. Run gradlew shadowJar to produce jar file for project
  3. Run the app with java -jar app/build/libs/app-all.jar
  4. Note the output which shows the command printed fails with an exit code 1 (because there are no results returned by the git command)
$ java -jar app/build/libs/app-all.jar
HELLOOOOOO
WD:::  null
[git, --no-pager, grep, --line-number, --untracked, --extended-regexp, "^\s*public void\s+(testAppHasAGreeting)\(\).*", --, *Test.java]
WD:::  /Users/rgurney/Src/personal/min-example

Exception in thread "main" java.lang.RuntimeException: org.apache.commons.exec.ExecuteException: Process exited with an error: 1 (Exit value: 1)
    at min.example.App.lambda$runCommand$1(App.java:74)
    at io.vavr.control.Try.getOrElseThrow(Try.java:748)
  1. Running the command manually does produce expected results:
$ git --no-pager grep --line-number --untracked --extended-regexp "^\s*public void\s+(testAppHasAGreeting)\(\).*" -- "*Test.java"
app/src/test/java/min/example/AppTest.java:11:    public void testAppHasAGreeting() {
8
  • 2
    Can you share a minimal reproducible example? Perhaps the way you're putting the CommandLine or Executor together are the problem Commented Dec 30, 2022 at 18:25
  • To follow up on my previous comment - I tested, and this most definitely works with Apache Commons Exec. I.e., the issue isn't the regex, but something else (perhaps the cwd? Perhaps handling the output?) We need to see a full example and the output that doesn't work for your usecase. Commented Dec 30, 2022 at 18:30
  • 1
    Thanks for taking a look @Mureinik. I added a rough MRE, which I think captures the problem. Commented Dec 30, 2022 at 19:18
  • No luck - I run the main in the sample you provided (using IntelliJ) and it just works. We're missing some environmental difference here. Commented Dec 30, 2022 at 19:44
  • 1
    Found it! I was testing on my Windows laptop. Once I switched over to my Linux desktop I was able to trivially reproduce the error with the instructions you provided. See my answer below for the details and the solution. Commented Dec 30, 2022 at 22:42

1 Answer 1

5
+50

I got a clue as to what's going on here when the sample you provided worked just fine on my Windows laptop but failed on my Linux desktop.

Once I made sure the git version wasn't the culprit (tested several versions between 2.17 and 2.39 on both machines), I figured the difference must be in the way different shells handle quoting. Specifically, the only argument here that has any potential quoting issues is the regex ("^\s*public void\s+(testFindByAdAccount).*"), which is added to the command line by commandLine.addArgument(regex);.

addArgument may look innocuous, but under the hood, it allows the CommandLine to handle the quoting itself (i.e., addArgument(String argument) calls addArgument(String argument, true). Since you've handled the quoting yourself, you should not allow the CommandLine to handle the quoting, and should explicitly call it with the second argument false. i.e.:

public static List<String> grep(String regex, String filePattern, String wd) {
    CommandLine commandLine = CommandLine.parse("git");
    commandLine.addArgument("--no-pager");
    commandLine.addArgument("grep");
    commandLine.addArgument("--line-number");
    commandLine.addArgument("--untracked");
    commandLine.addArgument("--extended-regexp");
    commandLine.addArgument(regex, false); 
    // Here -----------------------^
    commandLine.addArgument("--");
    commandLine.addArgument(filePattern);

    System.out.println(commandLine);

    return List.of(runCommand(commandLine, wd).split("\n"));
}

This takes the quote-handling logic away and ensures the same code runs smoothly both on Windows and Linux (at least those I've tested).

Sign up to request clarification or add additional context in comments.

1 Comment

My god. I tried so many permutations of the regex including manually adding quotes but never tried no quotes at all and adding false for handleQuoting. Confirmed working in both my MRE and my actual project. Thanks so much for this! Will award the bounty when the system allows in 17 hours.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.