-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Process] Allow writing portable "prepared" command lines #24763
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Process] Allow writing portable "prepared" command lines #24763
Conversation
2db2948
to
2c23e96
Compare
@@ -278,8 +278,13 @@ public function start(callable $callback = null, array $env = array()) | |||
|
|||
$options = array('suppress_errors' => true); | |||
|
|||
if ('\\' !== DIRECTORY_SEPARATOR) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about:
$windows = '\\' === DIRECTORY_SEPARATOR;
$this->replacePlaceholder($commandline, $windows ? array('!', '!') : array('$', ''));
if ($windows) {
|
||
private function replacePlaceholder($commandLine, $toReplace) | ||
{ | ||
if (preg_match('/\{([a-zA-Z0-9]*?)\}/', $commandLine)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either this test is useless (because {
or }
chars are replaced) or the following line is buggy (because {
and }
are replaced regardless that they match the previous regex).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From what I understand, it's buggy. Only placeholders like {foo}
must be replaced. {}
should not match, echo '{{foo}'
should return echo '{value'
too.
Something like this should do the trick:
if (!preg_match_all('/\{([a-zA-Z0-9]+?)\}/', $commandLine, $matches)) {
return $commandLine;
}
$patterns = $replacements = array();
foreach ($matches as $match) {
$patterns[] = sprintf('/{%s}/', $match[1]);
$replacements[] = sprintf('%s%s%s', $toReplace[0], $match[1], $toReplace[1]);
}
return preg_replace($patterns, $replacements, $commandLine);
(I've not tested it, but you got the idea)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand and will modify according to the exemple
e8973b5
to
0bf646c
Compare
done @dunglas |
Status: Needs Review |
0bf646c
to
c6c730c
Compare
|
||
private function replacePlaceholder($commandLine, $toReplace) | ||
{ | ||
if (!preg_match_all('/\{([a-zA-Z0-9]+?)\}/', $commandLine, $matches)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this could be replaced by a single call to preg_replace
the pattern is missing the underscore also
@@ -278,7 +278,10 @@ public function start(callable $callback = null, array $env = array()) | |||
|
|||
$options = array('suppress_errors' => true); | |||
|
|||
if ('\\' === DIRECTORY_SEPARATOR) { | |||
$windows = '\\' === DIRECTORY_SEPARATOR; | |||
$commandline = $this->replacePlaceholder($commandline, $windows ? array('!', '!') : array('$', '')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the "$toReplace" should be moved inside the method, there is no reason to leak this outside of the method I think
Someone proposed to fail when a var was used, but not provided when calling. Is that something that would be possible? |
I need to figure out, but I don't see anything that would make it not possible. |
ca1a267
to
51f6947
Compare
Comments addressed and new throw added. |
51f6947
to
0dda934
Compare
$patterns[] = sprintf('/{%s}/', $match[0]); | ||
$replacements[] = sprintf('%s%s%s', $toReplace[0], $match[0], $toReplace[1]); | ||
if (isset($env[$match[0]])) { | ||
$isInEnv = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't you store unused placeholders to display a nice error message like The placeholders "foo", "bar" doesn't exist
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can do that, that's a good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any update?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
0dda934
to
e596524
Compare
} | ||
|
||
if (!empty($env)) { | ||
throw new InvalidArgumentException(sprintf('Placeholder%s "%s" doesn\'t exist.', count($env) > 1 ? 's' : '', implode(',', array_keys($env)))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you make the distinction between singular and plural for "placeholder/s", you should probably do the same for "doesn't/don't" too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e596524
to
4bf2bb3
Compare
4bf2bb3
to
c49cbb6
Compare
Doc PR has been added. |
Thanks @Simperfit. |
…nes (Simperfit) This PR was merged into the 4.1-dev branch. Discussion ---------- [Process] Allow writing portable "prepared" command lines | Q | A | ------------- | --- | Branch? | 4.1 | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #23778 | License | MIT | Doc PR | symfony/symfony-docs#9295 This give the opportunity to create process commands that allow to changes only the values instead of changing the code. Commits ------- d1e4f48 [Process] Allow writing portable "prepared" command lines
I don't agree with this implementation. The new syntax is very specific to the Symfony process now and not suited within the a general Process class. This logic should be split out into some sort of ProcessBuilder that returns the final command line that you then pass to the Process. |
@Tobion you can think of this as SQL prepared statements. Note that the Process component doesn't provide any mean to escape shell arguments anymore, exactly like you should not use any for SQL drivers. And also because it is just impossible to properly escape shell arguments (same for SQL btw, when taking portability into account). |
PDO provides different methods for prepared statements to separate concerns. Exactly what I'm asking for. |
I'm really not convinced that a different design would provide anything better sorry. |
Late to the game, but isn't this a BC break for folks using something like |
There are probably bc breaks here. that is also why I don't agree with using the same api for this because you cannot control it anymore. |
Nobody echoes like that (they do |
I would expect that I can run a command with the process component the same way it works on the shell. This is not possible anymore and you have to think and know about Process special behavior now (in addition to correct escaping). |
do you have a real-life example? |
This is rather bold statement. Also I'm not talking about escaping, in my example the user would want to have plain IMO if you're not willing to revert the feature there should be a feature flag turned off by default in 4.x and switched to on in 5.x. |
@malarzm you were asking about BC break. I explained why I think the collision is more theoretical than practical IMHO. |
|
@Tobion sure, but this a constructed example... |
It's not about if it's real example or not. It's about expectations. Why am I not allowed to run a process that works with the process component? The job of the process component is it make it easier to run processes from PHP, not harder with edge cases that don't work and behave unexpected. |
I think Tobias has a point here. Suddenly, your Symfony app can't run commands that contain |
OK, see #26344 |
…e "prepared" command lines (Simperfit)" (nicolas-grekas) This PR was merged into the 4.1-dev branch. Discussion ---------- Revert "feature #24763 [Process] Allow writing portable "prepared" command lines (Simperfit)" | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - This reverts commit 1364089, reversing changes made to e043478. As discussed in #24763 and #26344 This doens't revert the possibility to use prepared command lines. They just won't be *portable* anymore, unless special care is taken by "userland". Ie the placeholders need to be shell-dependent: use eg `echo "$FOO"` on *nix (the double quotes *are* important), and `echo !FOO!` on Windows (no double quotes there). Commits ------- 6a98bfa Revert "feature #24763 [Process] Allow writing portable "prepared" command lines (Simperfit)"
…nes (Simperfit) This PR was merged into the 4.4 branch. Discussion ---------- [Process] Allow writing portable "prepared" command lines | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | no | New feature? | yes <!-- please update src/**/CHANGELOG.md files --> | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | #23778 <!-- #-prefixed issue number(s), if any --> | License | MIT | Doc PR | symfony/symfony-docs#11802 <!-- required for new features --> Hey here, it's me, again ! I've talked with @nicolas-grekas and he gave me a new way of writing this feature that will not be a problem for people using things like {{ toto }} since we are using the linux style of using envvar, the replaced arguments is only replaced when using windows. This should not break anything and work as expected! see #24763 This makes `"$FOO"` work seamlessly on Linux and on Windows to reference an env var (that can be provided when calling e.g. the "run" method) Commits ------- 3f8354f [Process] Allow writing portable "prepared" command lines
This give the opportunity to create process commands that allow to changes only the values instead of changing the code.