Update ::url_stat() for directories#16
Conversation
|
@BrianHenryIE I've created a |
|
Ok, I was able to do that here in the GitHub UI – I had branched from the 0.4.0. tag earlier, so no need for a rebase per se. If you're curious what I'm doing – I'm writing a |
|
@BrianHenryIE I'm running your branch against PHP 7.4.33, Xdebug 3.1.6, and Flysystem 2.5.0. With no changes to the existing test suite, this line isn't covered. I tried making the following modifications to an existing test in attempt to get that coverage. diff --git a/tests/StreamWrapperTest.php b/tests/StreamWrapperTest.php
index 2d24b3a..584572d 100644
--- a/tests/StreamWrapperTest.php
+++ b/tests/StreamWrapperTest.php
@@ -40,11 +40,14 @@ afterEach(function () {
$this->registry->unregister('fly');
});
-it('can create and delete directories', function () {
+it('can detect, create, and delete directories', function () {
+ $this->assertFalse(is_dir('fly://foo'));
$result = mkdir('fly://foo');
expect($result)->toBeTrue();
+ $this->assertTrue(is_dir('fly://foo'));
rmdir('fly://foo');
-});
+ $this->assertFalse(is_dir('fly://foo'));
+})->only();
it('handles opening a nonexistent directory', function () {
$dir = opendir('fly://foo');Unfortunately, the test fails, and I'm having trouble sorting out why. Any ideas? |
|
I noticed the directory created was called
But... as in #9, $this->filesystem = new Filesystem(
new \League\Flysystem\Local\LocalFilesystemAdapter(
sys_get_temp_dir() . '/' . uniqid('flystream')
),
[],
$pathNormalizer
);I'll take a look at backporting your |
|
I think this is ready to go now. |
| $this->assertTrue(is_dir('fly://foo')); | ||
| $rmResult = rmdir('fly://foo'); | ||
| expect($rmResult)->toBeTrue(); | ||
| clearstatcache(); |
There was a problem hiding this comment.
@BrianHenryIE I'm wondering if this clearstatcache() call shouldn't be in StreamWrapper->rmdir() instead?
Below are some related bits of a conversation I had with Edorian in the #help channel on the phpcommunity.org Discord earlier about this. Please give them a look and let me know what you think.
statcacheonly every caches the last accessed file/dir. Some references:
rmdir: https://github.com/php/php-src/blob/064ea9c505889fb84b2b3fc41230be26cc58a345/ext/standard/file.c#L1152
unlink: https://github.com/php/php-src/blob/064ea9c505889fb84b2b3fc41230be26cc58a345/ext/standard/file.c#L1300Which should go through https://github.com/php/php-src/blob/38501ed48a6a8d9ad57605d6a49e796230ac4b42/main/php_streams.h#L158 and end up :
plain_files_unlinkhttps://github.com/php/php-src/blob/0fe3a91494e9aece3ae948cf9bf9d3476686e0a5/main/streams/plain_wrapper.c#L1269
php_plain_files_rmdirhttps://github.com/php/php-src/blob/0fe3a91494e9aece3ae948cf9bf9d3476686e0a5/main/streams/plain_wrapper.c#L1500On empty directories everything looks fine to me:
<?php $dir = __DIR__ . '/tmp'; @rmdir($dir); mkdir($dir); var_dump("Exists:"); var_dump(stat($dir)['mtime']); rmdir($dir); var_dump("Cached?"); var_dump(stat($dir)['mtime']);=> php foo.php string(7) "Exists:" int(1738881324) string(7) "Cached?" PHP Warning: stat(): stat failed for /Users/edo/private/experiments/tmp in /Users/edo/private/experiments/foo.php on line 14So the second
statcall is not stale/cached information?https://www.php.net/manual/en/streamwrapper.rmdir.php doesn't mention this, but I'm guessing that an implementation of
streamWrapper->rmdir()has to handle callingclearstatcache()internally rather than PHP handling it automatically.Custom stream wrapper don't have to work on a local (or any) file system, so I don't think they can do anything automatically.
But if you call underlying system functions for file manipulation these should do a
clearstatcachethen. (LikeLocalFilesystemAdaptershould do?)Yeah looks like you're right on
url_statbeing cached by stat cache<?php $x = new class { public $context; public function url_stat(string $path, int $flags): array|false { var_dump("url_stat: $path"); return []; } }; stream_wrapper_register('test', get_class($x)); $dir = 'test://foo/bar'; var_dump(is_dir($dir)); var_dump(is_dir($dir)); var_dump(is_dir($dir));=> php foo.php string(24) "url_stat: test://foo/bar" bool(false) bool(false) bool(false)But here neither unlink nor rmdir clears the stat cache with a trivial implementation by its self:
So yeah, with the added context of this being stream wrappers this makes more sense
From what I can see for stream wrappers this isn't done by php, the reasoning for that is beyond me though (or my tests are wrong somehow).
There was a problem hiding this comment.
I agree, whether or not we expect it to be done by PHP, evidently it's leaving stat cache in an invalid state, so it seems correct to clear it inside StreamWrapper->rmdir().
|
|
|
@BrianHenryIE I've released this change in versions 0.5.0 and 1.3.0. Thanks again for your contribution! |

I don't seem to be able to specify 0.4.0 as the target for the PR.
::directoryExists()is a Flysystem 3.0 function which I call when it's available, otherwise I have a re-implementation.This is working well in my integration tests for BrianHenryIE/strauss#139
Closes #15 !