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

Skip to content

[Filesystem] Fixed makePathRelative #22321

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

Closed
wants to merge 11 commits into from
Closed

Conversation

ausi
Copy link
Contributor

@ausi ausi commented Apr 6, 2017

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

Updating to Symfony 3.2.7 @agoat noticed a bug with Filesystem::makePathRelative() in contao/core-bundle#751:

  • In Symfony 3.2.6 makePathRelative('aa/cc', 'bb/cc') returned correctly ../../aa/cc
  • In Symfony 3.2.7 the same method call returns ./

I think this issue was introduced with #22133.

While working on the fix I noticed some other issues too:

  • An unnecessary if construct that did nothing, fc745f4
  • Missing normalization of ./ path segments, 15982d4
  • ../ got ignored at the beginning of relative paths, 9586e88
  • The documentation of the method only allowed absolute paths, but there are already unit tests (FilesystemTest.php:1097) that test the behavior of relative paths, cec473e

This pull request fixes all these issues and adds tests for them.

@ausi ausi changed the title Fix/make path relative [Filesystem] Fixed makePathRelative Apr 6, 2017
@agoat
Copy link

agoat commented Apr 6, 2017

+1

@LinkingYou
Copy link

+1

* @param string $endPath Absolute path of target
* @param string $startPath Absolute path where traversal begins
* @param string $endPath Path of target
* @param string $startPath Path where traversal begins
Copy link
Member

Choose a reason for hiding this comment

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

This is a BC break. The method expects the paths to be absolute as documented.

Copy link

Choose a reason for hiding this comment

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

Well, then this should definitely be mentioned in the documentation. There's no hint that only absolute paths are targeted besides this inline doc comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why is this a BC break? Absolute paths work the same way as they did before.

Relative paths worked in the past and there are already unit tests (FilesystemTest.php:1097) that test the behavior of relative paths, so I think they should be allowed in the documentation of the method.

If relative paths should not be supported, I think we would have to throw an exception if a relative path gets passed, but that would be a BC break I think.

Copy link

Choose a reason for hiding this comment

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

It should support relative paths for some reasons:

  1. It worked before 3.2.7!
  2. Absolute paths will still work (No BC break).
  3. As @loilo mentioned, the documentation doesn't tell that only absolute paths can be used.
  4. It makes life easier (Otherwise everyone have to do extra checks on absolute paths, before using this method).

Copy link
Member

Choose a reason for hiding this comment

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

I didn't see that test case initially. I'm this case, we IMO should indeed support this and update the docblock as suggested. But I think we should indeed think about deprecating this behaviour.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Adding the “Absolute” back should then be part of #24202 I think. Otherwise I would have to remove the unit tests as @chalasr wrote in #22321 (comment)

Copy link
Member

Choose a reason for hiding this comment

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

I see it different here: "Absolute" should still be part of the docblock to make our intent clear that we want this method to receive absolute paths. People who not look at the tests do not need to know that this currently works with relative paths too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@chalasr explicitly wrote:

Tests should respect the contract which is to pass an absolute path.

Please discuss this with @chalasr first. I don’t want to change this pull request every two weeks. If you both agree, I can change the doccomment to whatever you want :)

Copy link
Member

Choose a reason for hiding this comment

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

Just discussed with @xabbuh and we come to the conclusion that the docblock clearly states the passed path must be absolute, that has been decided when introducing the method and should not be changed now.
Given we have a test in place for relative paths, let's improve the current implementation regarding relative paths as done here, so we can officially deprecate passing relative paths to the method in #24202 (or officially support any path, changing the docblock, but I don't think it's the right direction as currently discussed on the PR) and move forward.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I restored the original doccomment in 193cdf8 now.
@chalasr @xabbuh is this pull request now ready to be approved?

@@ -878,6 +879,17 @@ public function providePathsForMakePathRelative()
array('C:/aa/bb/../../cc', 'C:/aa/../dd/..', 'cc/'),
array('C:/../aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'),
array('C:/../../aa/../bb/cc', 'C:/aa/dd/..', '../bb/cc/'),
array('aa/bb', 'aa/cc', '../bb/'),
Copy link
Member

Choose a reason for hiding this comment

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

This is not something that is supported. The docblock states that the paths have to be absolute.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There was already an existing unit test (FilesystemTest.php:1097) that tested relative paths.

Copy link
Member

Choose a reason for hiding this comment

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

Let's not add new ones. Tests should respect the contract which is to pass an absolute path.

Copy link
Contributor

Choose a reason for hiding this comment

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

@chalasr the function always supported relative paths (before 3.2.7). There are even pre-existing test cases for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tests should respect the contract which is to pass an absolute path.

@chalasr Should I remove the pre-existing relative path tests then too? Or should I just remove the relative path tests that I added?

Copy link
Member

Choose a reason for hiding this comment

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

Can you please provide a new link to this test? Previous one is outdated and I can't find it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it’s line 1102 in the current master branch:

array('var/lib/symfony/', 'var/lib/symfony/src/Symfony/Component', '../../../'),

Copy link
Member

Choose a reason for hiding this comment

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

Indeed, it should be removed (we did revert a similar test for the very same reason #22133 (comment)). It's safe to do it here I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in a2a1d0d

Copy link
Member

Choose a reason for hiding this comment

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

@chalasr Actually, the example that you gave was a test I mistakenly added in that very same PR. So it was never part of a merge. :)

@@ -358,34 +358,37 @@ public function makePathRelative($endPath, $startPath)
$startPath = str_replace('\\', '/', $startPath);
}

$stripDriveLetter = function ($path) {
if (strlen($path) > 2 && substr($path, 1, 2) === ':/' && ctype_alpha($path[0])) {
Copy link
Member

Choose a reason for hiding this comment

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

instead of substr() I suggest to use ':' === $path[1] && '/' === $path[2]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I used substr() because it’s done that way in isAbsolutePath() Filesystem.php:587. Should I change it though?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should I change the substr() to ':' === $path[1] && '/' === $path[2] to get this pull request approved?

Copy link
Member

Choose a reason for hiding this comment

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

👍 for @xabbuh's suggestion

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in bce33c4

@ausi
Copy link
Contributor Author

ausi commented Jun 9, 2017

@xabbuh any updates on this? Can I do something to get this bugfix merged?

@robfrawley
Copy link
Contributor

Overall, I love the bug fixes introduced in this PR with regard to relative paths. That said, it seems weird to allow empty input and expect any meaningful output.

Start End Expected
"" "" "./"
"aa/" "" "../"
"" "aa/" "aa/"

Does this really make sense? Should passing empty strings be deprecated? I wouldn't say that most people would expect these outputs and it would likely just hide a bug within their API usage, IMHO.

@ausi
Copy link
Contributor Author

ausi commented Jun 10, 2017

I think it should be allowed to pass an empty string. If "aa/" is a valid path then "" should be too, otherwise every developer that uses this method has to handle empty strings themselves. Your three examples are prefectly fine for me, did you expect any different output?

But I think there are cases that cannot produce a meaningful result, like start "../../" and end "../". For these cases it might make sense to throw an exception.

@ausi
Copy link
Contributor Author

ausi commented Aug 7, 2017

Is there anything I can do to get these fixes merged?

* @param string $endPath Absolute path of target
* @param string $startPath Absolute path where traversal begins
* @param string $endPath Path of target
* @param string $startPath Path where traversal begins
Copy link
Member

@chalasr chalasr Aug 8, 2017

Choose a reason for hiding this comment

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

This should be reverted, if we have to support it fully that should be discussed separately and done on 3.4, as said above.

@@ -878,6 +879,17 @@ public function providePathsForMakePathRelative()
array('C:/aa/bb/../../cc', 'C:/aa/../dd/..', 'cc/'),
array('C:/../aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'),
array('C:/../../aa/../bb/cc', 'C:/aa/dd/..', '../bb/cc/'),
array('aa/bb', 'aa/cc', '../bb/'),
Copy link
Member

Choose a reason for hiding this comment

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

Let's not add new ones. Tests should respect the contract which is to pass an absolute path.

@xabbuh
Copy link
Member

xabbuh commented Aug 10, 2017

Does the PR now still solve anything at all? I miss a new test case that would fail otherwise.

@ausi
Copy link
Contributor Author

ausi commented Aug 10, 2017

Yes, it still solves all the issues described in the initial issue comment. Especially the BC break that was introduced in 3.2.7. I removed the test cases because @chalasr requested that I should add them in a feature pull request for version 3.4.

@xabbuh
Copy link
Member

xabbuh commented Aug 10, 2017

Well, but it doesn't make sense to introduce a bugfix that in fact implements a feature that should be part of 3.4. So we need to decide whether not fully supporting relative path arguments was a BC break (because we had tests for relative paths despite the API docs telling the opposite) or if that is a new feature. And then there should be one PR containing proper tests for what the code change does achieve.

ping @symfony/deciders

@ausi
Copy link
Contributor Author

ausi commented Aug 10, 2017

I agree, that’s why my pull request included the doccomment change and the tests in the first place.

IMO the “feature” that relative paths are supported was always there (including a unit test) and got broken in 3.2.7.

Should I remove 193cdf8 and a2a1d0d from this pull request?

@@ -845,7 +845,6 @@ public function providePathsForMakePathRelative()
array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component/', '../'),
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we have simple case array('aa', 'bb', '../aa/'), as this is example of what installRequirementsFile from Sensio\Bundle\DistributionBundle\Composer\ScriptHandler is breaking in composer script in latest Symfony?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, this does work with my fixes. But if relative paths should be supported at all is currently in discussion as you can see in the comments of this pull request.

@xelaris
Copy link
Contributor

xelaris commented Aug 14, 2017

As mentioned by @kubawerlos the SensioDistributionBundle relies on support for relative paths, when calling Filesystem::makePathRelative with symfony-var-dir and symfony-bin-dir from the extra settings in the composer.json (usually "var" and "bin").
When composer 1.5.0 was released a week ago, the version of symfony/filesystem included changed from v2.8.18 to v2.8.26. Since then the SensioDistributionBundle generates wrong require statements for SymfonyRequirements.php. Corresponding issues (sensiolabs/SensioDistributionBundle#324 and composer/composer#6599) were created in these repositories.

@ausi
Copy link
Contributor Author

ausi commented Sep 10, 2017

So there are already two known projects that got broken because of this issue. Wouldn’t it make sense to merge this?

Should I remove 193cdf8 and a2a1d0d from this pull request?

I removed these commits now from this pull request.

@kubawerlos
Copy link
Contributor

Haven't been tracing this, but in Symfony 3.3.8 it's back to correct paths.

@ausi
Copy link
Contributor Author

ausi commented Sep 10, 2017

@kubawerlos I don’t see any change to the makePathRelative() method since version 3.2.7, could you point to the commit where it got fixed?

What is the result of makePathRelative('aa/cc', 'bb/cc') in your installation?

@kubawerlos
Copy link
Contributor

@ausi just found it, it was fixed directly in SensioDistributionBundle, so the problem still exists here.

ausi referenced this pull request in sensiolabs/SensioDistributionBundle Sep 13, 2017
@ausi
Copy link
Contributor Author

ausi commented Sep 16, 2017

@chalasr your review status still shows up as “requested changes”, are there any changes I’ve forgotton?

@fabpot
Copy link
Member

fabpot commented Sep 17, 2017

Thank you @ausi.

fabpot added a commit that referenced this pull request Sep 17, 2017
This PR was squashed before being merged into the 2.7 branch (closes #22321).

Discussion
----------

[Filesystem] Fixed makePathRelative

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

Updating to Symfony 3.2.7 @agoat noticed a bug with `Filesystem::makePathRelative()` in contao/core-bundle#751:

- In Symfony 3.2.6 `makePathRelative('aa/cc', 'bb/cc')` returned correctly `../../aa/cc`
- In Symfony 3.2.7 the same method call returns `./`

I think this issue was introduced with #22133.

While working on the fix I noticed some other issues too:

- An unnecessary if construct that did nothing, fc745f4
- Missing normalization of `./` path segments, 15982d4
- `../` got ignored at the beginning of relative paths, 9586e88
- The documentation of the method only allowed absolute paths, but there are already unit tests ([FilesystemTest.php:1097](https://github.com/symfony/symfony/blob/ab93feae3f9a16c4f18c5736435d18fa36338d2c/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php#L1097)) that test the behavior of relative paths, cec473e

This pull request fixes all these issues and adds tests for them.

Commits
-------

2bc1150 [Filesystem] Fixed makePathRelative
@fabpot fabpot closed this Sep 17, 2017
This was referenced Oct 5, 2017
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.