Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Finder] Fixed leading/trailing / in filename #26337

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

Merged
merged 1 commit into from
Mar 20, 2018
Merged

Conversation

lyrixx
Copy link
Member

@lyrixx lyrixx commented Feb 27, 2018

Q A
Branch? 2.7
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets
License MIT
Doc PR

Without this patch, we go this:

--- Expected
+++ Actual
@@ @@
 Array (
-    0 => '/tmp/symfony_finder/foo bar'
-    1 => '/tmp/symfony_finder/foo/bar.tmp'
-    2 => '/tmp/symfony_finder/test.php'
-    3 => '/tmp/symfony_finder/test.py'
+    0 => '///tmp/symfony_finder///foo bar'
+    1 => '///tmp/symfony_finder///foo/bar.tmp'
+    2 => '///tmp/symfony_finder///test.php'
+    3 => '///tmp/symfony_finder///test.py'
 )


$expected = $this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py', 'foo bar'));
$in = realpath(self::$tmpDir);
$in = '//'.realpath(self::$tmpDir).'//';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I removed my previous comment by mistake. It's ok for me if this variable override is fixed 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, fixed

@@ -28,7 +28,7 @@ class SplFileInfo extends \SplFileInfo
*/
public function __construct($file, $relativePath, $relativePathname)
{
parent::__construct($file);
parent::__construct(realpath($file));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

realpath($file) ?: $file?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

realpath() if $file is symlik will return path to original path and if try to remove symlink $file it will be remove original file. so question: how now remove only sumlink without original path?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

realpath usage was reverted already ;)

@Simperfit
Copy link
Contributor

Could you please check AppVeyor, it seems that the broken tests are related to this patch ?

$finder = $this->buildFinder();

$expected = $this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py', 'foo bar'));
$in = '//'.realpath(self::$tmpDir).'//';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding // at the beginning of a Windows absolute path won't produce a valid path. So this test must be skipped on Windows.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Fixed

@nicolas-grekas
Copy link
Member

a test case is failing though

Without this patch, we go this:

```
--- Expected
+++ Actual
@@ @@
 Array (
-    0 => '/tmp/symfony_finder/foo bar'
-    1 => '/tmp/symfony_finder/foo/bar.tmp'
-    2 => '/tmp/symfony_finder/test.php'
-    3 => '/tmp/symfony_finder/test.py'
+    0 => '///tmp/symfony_finder///foo bar'
+    1 => '///tmp/symfony_finder///foo/bar.tmp'
+    2 => '///tmp/symfony_finder///test.php'
+    3 => '///tmp/symfony_finder///test.py'
 )
```
@lmanzke
Copy link

lmanzke commented Apr 3, 2018

IMO, one trailing slash is not a bug (I definitely would say that it is good practice to have it there!). The bug is reproducing the slash multiple times.

Furthermore, it is not an implementation detail. To me, the finder is a complete blackbox, actually. I never studied the code, to be honest, so, in fact, I cannot know any implementation details. It is like a function that I call - I use the results without caring how it came about. For example, the function double(x) = 2 * x that becomes double(x) = 2.0 * x - changing the return type from int to float. (Do not take this comparison too seriously, it's more of a metaphorical nature). Suppose there is no explicit contract that the return type of this function is an int, then there might be code implicitly building on that fact, without it ever being stated anywhere. For me, that about sums up the problem I have with that kind of change. To me, it's not an implementation and definitely not a bug that a path contains one(!) trailing directory separator. That might be a matter of opinion though.

I'd also like to point out that my life goes on whether this PR is merged or not - it's more a question of principle that we are discussing at the moment.

In essence, we can agree that not ensuring that a path ends (or doesn't end) with a slash (whatever the expected behavior is) is careless and dangerous. But it happens - and when it does, then changing the current behavior might come unexpected to some users. The only thing I can ask for is careful thought about the consequences - advantages and disadvantages alike.

@lyrixx
Copy link
Member Author

lyrixx commented Apr 3, 2018

About the trailing slash or not and why I made this PR:

During some trainings, I use to make a simple exercice: use the console and the finder to list all PHP files in a directory.

Here is the code:
<?php

namespace App\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Finder\Finder;

class FinderExerciseCommand extends Command
{
    protected static $defaultName = 'app:finder:exercise';

    protected function configure()
    {
        $this
            ->setDescription('Finder playground')
            ->addArgument('dir', InputArgument::REQUIRED, 'Le dossier a scanner')
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $dir = $input->getArgument('dir');

        $files = Finder::create()
            ->in($dir)
            ->name('*.php')
        ;

        $io = new SymfonyStyle($input, $output);
        $io->listing(iterator_to_array($files));
    }
}

And before the patch, here is output of the following command: bin/console app:finder:exercise src/:

 * src//Command/ExerciceCommand.php
 * src//Command/DoctrineExerciseCommand.php
 * src//Command/FinderExerciseCommand.php
{...}

Did you notice the double /? To me it's a bit ugly.
The same "error" occurs in PHP-CS-fixer. For example:

$ php-cs-fixer fix src/ 
Loaded config default.
   1) src//Command/FinderExerciseCommand.php

@stof
Copy link
Member

stof commented Apr 3, 2018

@lmanzke PHP itself will never return a trailing slash for APIs returning a directory name (dirname, SplFileInfo::getPath, __DIR__ etc...). So writing your code in a way not adding the separator in the concatenation is actually relying on an implementation detail here (if you don't rely on it, you would be adding a separator in the concatenation to be safe)

@lmanzke
Copy link

lmanzke commented Apr 3, 2018

The argument of consistence with PHP makes sense, although some of its design choices might be questionable in some instances ;). But that's besides the point, not the right place and time to discuss this rather semantic matter ;).

@lyrixx
Copy link
Member Author

lyrixx commented Apr 3, 2018

It may be questionable, but it's really common to not add the trailing slash in the unix philosophy.
Some sample:

>[/home/gregoire] readlink -f dev/
/home/gregoire/dev

>[/home/gregoire] ll dev/
total 24K
drwxr-xr-x 51 gregoire gregoire 4,0K Jan 10 15:56 debug
{...}

>[/home/gregoire] basename dev/
dev

>[/home/gregoire] dirname dev/
.

If you use low level tools like strace the trailing slash is always omitted.

And IIRC, Python, Ruby, ... omit it too.


Anyway, as you said, it's not the place to discuss about PHP design choices ;)

Now Symfony is just consistant with PHP and unix philosophy

@lmanzke
Copy link

lmanzke commented Apr 3, 2018

In this instance, it makes perfect sense. Thank you.

@bobdenotter
Copy link
Contributor

We're still investigating, but it seems like this breaks updates in Bolt too. First tests indicate adding "symfony/finder": "^2.8, !=2.8.37" in composer.json resolves the issue.

@helhum
Copy link
Contributor

helhum commented Apr 3, 2018

@lmanzke @fabpot

foreach (Finder::create()->dir()->in($dir) as $dir) { $file = $dir.$file; }

This code never worked, so there is no need to discuss whether it should work from a bc promise perspective.

The found directories never contained a trailing slash.

This behavior is on par with native PHP code like:

foreach (new \DirectoryIterator(__DIR__) as $fileInfo) {
    if ($fileInfo->isDir() && !$fileInfo->isDot()) {
        echo $fileInfo->getPathname() . PHP_EOL;
    }
}

Output (__DIR__ in this example is Symfony main repo folder):

...
/Symfony/symfony/src
/Symfony/symfony/vendor

Also no trailing slash on found directories.

Let's look at the symfony/finder counterpart of that code:

$finder = \Symfony\Component\Finder\Finder::create();
$finder
    ->directories()
    ->depth(0)
    ->in(__DIR__);

foreach ($finder as $item) {
    /** @var \Symfony\Component\Finder\SplFileInfo $item */
    echo $item->getPathname() . PHP_EOL;
}

Output:

...
/Symfony/symfony/src
/Symfony/symfony/vendor

Same output, no trailing and no duplicate slashes, all good.

But if we now change the input directory to have a trailing slash, we get different result with finder compared with native PHP iterator:

foreach (new \DirectoryIterator(__DIR__.'/') as $fileInfo) {

Output:

/Symfony/symfony/src
/Symfony/symfony/vendor

->in(__DIR__.'/');

Output:

/Symfony/symfony//src
/Symfony/symfony//vendor

If I understand @lyrixx correctly, it was their intention to fix exactly that, not having duplicate slashes here.

The fix however (applying realpath to the complete resulting path in SplFileObject), introduced an unwanted side effect:

foreach (new \DirectoryIterator(__DIR__.'/../symfony/') as $fileInfo) {

Output:

/Symfony/symfony/../symfony/src
/Symfony/symfony/../symfony/vendor

->in(__DIR__.'/');

Output:

/Symfony/symfony/src
/Symfony/symfony/vendor

The unwanted side effect is, that the base path (search dirs) was normalized (using realpath) as well.

That side effect obviously broke quite some userland code, most likely because this code assumed that the resulting found paths have the same prefix as the given input paths.

I'd argue that this indeed is a BC break that needs a revert, especially also because the introduced behavior differs from native PHP implementation and also because $fileInfo->getPathname() effectively became an alias to $fileInfo->getRealPath(), because getPathname also returned the realpath. it does not make much sense to have two getters returning the same values in all cases.

That is why I trimmed the input values to in() in the PR I proposed

This approach keeps the input/base path intact, but avoids having duplicate slashes in the results in case the input value had a trailing slash. (Which, again, is what @lyrixx intended to fix).

Hope that clarifies what happened and how (I think) it should be fixed.

fabpot added a commit that referenced this pull request Apr 4, 2018
This PR was squashed before being merged into the 2.7 branch (closes #26763).

Discussion
----------

[Finder] Remove duplicate slashes in filenames

| Q             | A
| ------------- | ---
| Branch?       | 2.7 up to 4.0
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #26757
| License       | MIT

This PR takes another approach to fix in excess slashes in Finder than #26337
which does a simple rtrim instead of the breaking realpath.

Commits
-------

cdde6d9 [Finder] Remove duplicate slashes in filenames
@fabpot
Copy link
Member

fabpot commented Apr 4, 2018

#26763 should fix the issue.

@helhum helhum mentioned this pull request Apr 4, 2018
reviewtypo3org pushed a commit to TYPO3/typo3 that referenced this pull request Apr 4, 2018
A regression was introduced in symfony/finder
symfony/symfony#26337

This caused PackageManager to not find any core packages
any more in case they were symlinked.

Composer command (after adding conflict):
composer update --lock

Resolves: #84601
Releases: 7.6, 8.7, master
Change-Id: I914c3b3c4a6c12375ebd9fe5442c3f7ff407de72
Reviewed-on: https://review.typo3.org/56541
Reviewed-by: Mathias Brodala <[email protected]>
Tested-by: TYPO3com <[email protected]>
Reviewed-by: Nicole Cordes <[email protected]>
Tested-by: Nicole Cordes <[email protected]>
Reviewed-by: Georg Ringer <[email protected]>
Tested-by: Georg Ringer <[email protected]>
Reviewed-by: Stefan Neufeind <[email protected]>
Tested-by: Stefan Neufeind <[email protected]>
TYPO3IncTeam pushed a commit to TYPO3-CMS/core that referenced this pull request Apr 4, 2018
A regression was introduced in symfony/finder
symfony/symfony#26337

This caused PackageManager to not find any core packages
any more in case they were symlinked.

Composer command (after adding conflict):
composer update --lock

Resolves: #84601
Releases: 7.6, 8.7, master
Change-Id: I914c3b3c4a6c12375ebd9fe5442c3f7ff407de72
Reviewed-on: https://review.typo3.org/56541
Reviewed-by: Mathias Brodala <[email protected]>
Tested-by: TYPO3com <[email protected]>
Reviewed-by: Nicole Cordes <[email protected]>
Tested-by: Nicole Cordes <[email protected]>
Reviewed-by: Georg Ringer <[email protected]>
Tested-by: Georg Ringer <[email protected]>
Reviewed-by: Stefan Neufeind <[email protected]>
Tested-by: Stefan Neufeind <[email protected]>
reviewtypo3org pushed a commit to TYPO3/typo3 that referenced this pull request Apr 4, 2018
A regression was introduced in symfony/finder
symfony/symfony#26337

This caused PackageManager to not find any core packages
any more in case they were symlinked.

Composer command (after adding conflict):
composer update --lock

Resolves: #84601
Releases: 7.6, 8.7, master
Change-Id: I914c3b3c4a6c12375ebd9fe5442c3f7ff407de72
Reviewed-on: https://review.typo3.org/56548
Reviewed-by: Helmut Hummel <[email protected]>
Tested-by: Helmut Hummel <[email protected]>
reviewtypo3org pushed a commit to TYPO3/typo3 that referenced this pull request Apr 4, 2018
A regression was introduced in symfony/finder
symfony/symfony#26337

This caused PackageManager to not find any core packages
any more in case they were symlinked.

Composer command (after adding conflict):
composer update --lock

Resolves: #84601
Releases: 7.6, 8.7, master
Change-Id: I914c3b3c4a6c12375ebd9fe5442c3f7ff407de72
Reviewed-on: https://review.typo3.org/56549
Tested-by: TYPO3com <[email protected]>
Reviewed-by: Helmut Hummel <[email protected]>
Tested-by: Helmut Hummel <[email protected]>
TYPO3IncTeam pushed a commit to TYPO3-CMS/core that referenced this pull request Apr 4, 2018
A regression was introduced in symfony/finder
symfony/symfony#26337

This caused PackageManager to not find any core packages
any more in case they were symlinked.

Composer command (after adding conflict):
composer update --lock

Resolves: #84601
Releases: 7.6, 8.7, master
Change-Id: I914c3b3c4a6c12375ebd9fe5442c3f7ff407de72
Reviewed-on: https://review.typo3.org/56548
Reviewed-by: Helmut Hummel <[email protected]>
Tested-by: Helmut Hummel <[email protected]>
@lmanzke
Copy link

lmanzke commented Apr 7, 2018

Actually I found out that the code sample provided by @fabpot indeed never worked. The problem was the getPath() method on returned SplFileInfo objects.

@aschempp
Copy link
Contributor

aschempp commented Apr 9, 2018

@Imangazaliev can you elaborate on that? What is your problem exactly with getPath? Still having unwanted slashes or non-symlink files?

@lmanzke
Copy link

lmanzke commented Apr 9, 2018

Actually the slash was there at the end when calling getPath() on an SplFileInfo returned by finder. Now it is not there. While this is consistent, it caused some hidden problems which are now fixed :).

@helhum
Copy link
Contributor

helhum commented Apr 9, 2018

@lmanzke are you talking about the latest release (4.0.8) or the previous one? (4.0.7)

And can you provide the exact code you used, which broke (or still breaks?) for you?

@lmanzke
Copy link

lmanzke commented Apr 10, 2018

I will get back to you, I'm just very busy at the moment :).

@jfmaeck
Copy link

jfmaeck commented May 30, 2018

I think there might be a "real" BC break for those trying to list the contents of an FTP root directory. It seems that the trailing slash is required in this case.

See #27423

@DanielRuf
Copy link

I think there might be a "real" BC break for those trying to list the contents of an FTP root directory. It seems that the trailing slash is required in this case.

See #27423

It was already fixed and released as bugfix releases for all branches. ;-)

@jfmaeck
Copy link

jfmaeck commented May 30, 2018

@DanielRuf thanks for the hint.

Unfortunately, I cannot find the mentioned bug fix in the code and I am still getting the error using the latest 4.0 Version (4.0.11).

Or am I missing something?

@DanielRuf
Copy link

@jfmaeck see #26849

@jfmaeck
Copy link

jfmaeck commented May 31, 2018

Hi @DanielRuf as far as I can tell, the bug with the ftp root directory which requires the now stripped slash was released in #26849, not fixed.

@DanielRuf
Copy link

Imo this is not a regression and how it should work now. See the complete history of this issue here.

@jfmaeck
Copy link

jfmaeck commented May 31, 2018

OK, but how can I get the previously working (and documented) example of querying the contents in an FTP root directory fixed?

        $finder = new Finder();
        $files = $finder->files()->in('ftp://speedtest.tele2.net/');
        foreach ($files as $file) {
            var_dump($file);
        }

Or is this use case no longer supported? If that is the case then at least the documentation should be updated accordingly. It currently reads:

always add a trailing slash when looking for in the FTP root dir

(see https://symfony.com/doc/current/components/finder.html)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.