phingofficial / phing

PHing Is Not GNU make; it's a PHP project build system or build tool based on Apache Ant.
https://www.phing.info
GNU Lesser General Public License v3.0
1.16k stars 319 forks source link

Regression: empty argument in ExecTask cannot be escaped #1839

Open lpd-au opened 4 months ago

lpd-au commented 4 months ago

Describe the bug With Phing 2 it was possible to do this:

<target name="echo-old">
    <exec command="echo foo '' bar" passthru="true" />
</target>
<target name="php-old">
    <exec command="php -r 'var_dump($argv);' foo '' bar" passthru="true" />
</target>

This produced:

echo-old: foo  bar                                # Note: two spaces
php-old: array(4) {
  [0]=>
  string(19) "Standard input code"
  [1]=>
  string(3) "foo"
  [2]=>
  string(0) ""                                    # Note: length 0
  [3]=>
  string(3) "bar"
}

The documentation says it should still be possible with Phing 3:

To pass an empty argument, enclose two double quotes in single quotes ('""').

However, this produces a literal "" with any value of escape (including none); I cannot find a combination of attributes that produces the same behaviour as before.

Steps To Reproduce

<target name="echo">
    <exec executable="echo" passthru="true">
        <arg value="foo" />
        <arg value='""' />
        <arg value="bar" />
    </exec>
</target>
<target name="php">
    <exec executable="php" passthru="true">
        <arg value="-r" />
        <arg value="var_dump($argv);" escape="true" />
        <arg value="foo" />
        <arg value='""' />
        <arg value="bar" />
    </exec>
</target>

Expected behavior

echo: foo  bar
php: array(4) {
  [0]=>
  string(19) "Standard input code"
  [1]=>
  string(3) "foo"
  [2]=>
  string(0) ""
  [3]=>
  string(3) "bar"
}

Screenshots / terminal output

echo: foo "" bar
php: sh: 1: Syntax error: "(" unexpected
     [exec] Result: 2

Additional context Replacing the inline php with a file still outputs a non-zero length string:

php-file: array(4) {
  [0]=>
  string(8) "test.php"
  [1]=>
  string(3) "foo"
  [2]=>
  string(2) """"
  [3]=>
  string(3) "bar"
}
fredden commented 1 month ago

I've had a look into this. Initially I tried changing exec and passthru to use proc_open, where we can pass in the arguments individually rather than have a shell interpret a string, however that change is quite large and affects multiple other classes. It makes things a lot more robust and the "output" and "error" features are much cleaner this way, but I'm afraid that the change is too large for a patch version number. For reference, I have uploaded my current snapshot to https://github.com/phingofficial/phing/compare/main...fredden:phing:feature/gh-issue-1839 - but this is far from ready as several tests are still failing.

@mrook I can see that you've tagged this as a good first issue. Please can you provide some guidance on what you had in mind to fix this?

ralfstrobel commented 1 week ago

I have also been unsuccessfully trying to find a solution for this. We used to have several constructs such as the following:

<exec command="... -e '${exclude}'" />

It can be that the exclude property evaluates to an empty string, in which case -e '' would be the expected command line while simply omitting the empty string results in an error.

I have tried several approaches: