Closed (fixed)
Project:
Drupal core
Version:
8.8.x-dev
Component:
file system
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
23 Feb 2019 at 22:17 UTC
Updated:
7 Aug 2019 at 10:34 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
claudiu.cristeaAs it turned out in #1451320: Evaluate Symfony2's Finder Component to simplify file handling, file_scan_directory() is far more better in terms of performance. That we should preserve. But lacks DX. What if we create a component that is using file_scan_directory() implementation but on Finder interface so we’re compatible with the Symfony2 component and at some point, if they are solving their perfomance debt, we can easily drop our code but still keep the contract?
Comment #3
dww+1 to trying #2.
Comment #4
kim.pepperCurrently there are a few of issues we'd need to address:
Comment #5
kim.pepperGiven the above #4, I think we should move this to the file_system service instead.
Comment #6
kim.pepperHere's a patch that moves it to the file_system service.
Comment #8
andypostAs 8.8 branch is open - not sure what we should have in deprecation message
both services has fileSystem already injected
Comment #9
kim.pepper@andypost Happy to leave it on 8.7.0 until 11 March?
Also, any suggestions on how to handle FileTranslation? Looks like it's designed as a value object, but depends on a service? Do we inject FileSystem everywhere we see new FileTranslation()? or just convert FileTranslation to a service itself?
Comment #10
andypostLooks it should be 8.7 for a while!
I bet we should use the service methods instead, maybe convert it same time?
Comment #11
kim.pepperThanks @andypost. As discussed in slack, I went with the private function getFileSystem() approach.
Re: #10 there's a separate issue for that. Not clear to me whether this is related or not?
Comment #12
andypostRelated to 10, the problem here is that service should not use function from include which using the service and calls already deprecated stuff
Comment #14
kim.pepperDiscussed with @andypost in slack, I'd prefer the streamwrapper changes be done in #3034072: Move file uri/scheme functions from file.inc and FileSystem to StreamWrapperManager rather than here.
Fixes a few missing conversions.
Comment #15
kim.pepperAgreed with @andypost to wrap calls to file_stream_wrapper_uri_normalize() in a private method.
Comment #16
kim.pepperAdds links to https://www.drupal.org/node/3034072 in comments.
Comment #17
jibranOther then a minor question patch looks great. Thanks for working on it.
Why are we doing this here and not in constructor?
Comment #19
kim.pepper@jibran as per #8 and #9 FileTranslation is a value object, not a service, but depends on the file_system service. We are using a lazy loader approach here.
Comment #20
mile23It's 8.8.x now. :-)
#3034072: Move file uri/scheme functions from file.inc and FileSystem to StreamWrapperManager still waiting...
Use
@coversDefaultClassand/or@covers. Also, it doesn't test the interface.Comment #21
kim.pepperThanks for the review.
Comment #22
mile23Diggit.
Comment #24
kim.pepperFix incorrect syntax on the covers annotations.
Comment #26
naveenvalechaFixing the test
Comment #27
kim.pepperAs @Mile23 RTBC'd back in #23 I think we're safe to re-RTBC now.
Comment #28
dwwMostly looks great, thanks. Don't want to NW over this, but:
Generally don't we trigger a deprecation warning if the new arg isn't passed and we have to fall back to a default of NULL triggering \Drupal::service()?
I usually see that directly in the constructor, instead of needing the whole private getFileSystem() method.
Comment #29
cilefen commentedI don’t know what we gain in general by writing “deprecated in Drupal 8.7.0“ with a specific version (8.7.0). It will be deprecated whenever the deprecation is released, right?
Don’t change this patch because of this! But if anyone agrees with me we should open an issue to discuss.
Comment #30
berdirThe version number is crucial for contrib, because when you get deprecation messages, you need to know if you can actually act on them. For example, right now, it is too early to change code so it works only on 8.7, but in 6 month, you can add a version dependency on that and update your calls.
Also, it's a coding standard, see #3024461: Adopt consistent deprecation format for core and contrib deprecation messages.
Comment #31
kim.pepperRe: #28
The reason for the getFileSystem() is to lazily load the file system service. If we do it in the constructor, Symfony dependency injection detects a circular dependency and errors out.
Comment #32
dww@kim.pepper re: #31: Ok, makes sense. Thanks for the explanation. However, it seems we still want a deprecation warning, no?
Comment #33
kim.pepperRe: #32 Adds a @trigger_error to the getFileSystem() method.
Comment #35
andypostComment #36
dwwRe #33: Thanks and ouch: 1,567 fails... yikes. ;) I haven't tried to look into why this is failing so much. But, seems like a good thing we added the warning, since it's showing us that the patch isn't complete and something getting called frequently hasn't been updated as needed.
Comment #37
berdirWhy do we need this? Can't we just call the function until it becomes deprecated?
I don't understand the pattern here. We are we kinda injecting it but then still have a private method and deprecate it in there?
It has an existing constructor, so why don't we just put the deprecation message in there? Or we say we don't require it, but then we shouldn't deprecate it.
Comment #38
kim.pepperComment #39
claudiu.cristeaThe interface is a public contract. Parameters that are revealing an implementation detail (
$depth) should not be on the public contract. We should remove it and rework the implementation, probably by wrapping a protected helper method:doScanDirectory().Log or throw an exception? Have no idea if we can touch this but exception sounds better for me. Then we provide the BC in
file_scan_directory()by catching the exception and logging. I think this would needs sub-system maintainer advice.In see the BC is supported in signature but we have also to raise the red flag, i.e @trigger_error(). #37.2 was correct. We should drop the method and add the deprecation in the constructor, as usual.
default.settings.phpComment #40
claudiu.cristeaMore...
So... this is also weird and for sure it's a bug. If the directory doesn't exist or
$dirpoints to a file, rather than a directory, the method will still return an empty array ([]), same as in the case when is scanning an existing, empty directory. This is misleading. I think we have to throw an exception. Some could argue that this is off-topic and should be moved to a followup. But as this is a new service method, I think we should fix it here.Comment #41
dwwRe: #39.3 and #37.2: I raised this is in #28. See @kim.pepper's answer in #31:
Not sure I totally buy it, but that's the story.
Comment #42
berdir> FileTranslation is a special case where it is a value object that gets instantiated for a specific directory, but also calls a service internally.
I don't think it's really a value object, it *is* service, but it's only dynamically registered in install_begin_request() for example. I think it would be possible to inject the file_system there. But I'm also open to try that in a follow-up issue.
Comment #43
kim.pepperThanks for all your reviews!
Re: #39
Re: #40
I added a check for is_dir and created and throw a new NotRegularDirectoryException now. I've updated file_scan_directory() to catch this and return an empty array for BC.
Comment #44
kim.pepperSeems that the check for is_dir() is being relied on in a load of places throughout core. We can either:
Any preference?
Comment #45
kim.pepperI added a couple of is_dir() checks to see how broken things are.
Comment #46
kim.pepperTypo.
Comment #47
kim.pepperOK. Still getting lots of fails. See if this helps.
Comment #49
kim.pepperFix test fails in #47
Comment #50
martin107 commentedAfter a visual scan of the patch ... this looks like a good improvement.
a) The drive behind the issue is sound.
b) The implementation is good.
I have only a minor thing
The Drupal standard as encoded in phpcs now places a tight restraint on the text format of deprecation text.
drupal:8.7.0 (without capitalization ) is the main change needed. Here is a single example of the warnings generated by the patch.
507 | ERROR | [ ] The deprecation text '@deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Use
| | \Drupal\Core\File\FileSystemInterface::getDestinationFilename() instead.' does not match the standard
| | format: @deprecated in %in-version% and will be removed from %removal-version%. %extra-info%.
Comment #51
berdirdrupal:version is IMHO fine, I think the problem with the message is before => from.
Comment #52
claudiu.cristeaIt doesn't make sense to merge defaults and normalize
$options['key']on each recursion. We can move them in the main public method so that they run only once.This also can be moved in the public method to run only once. I'm also confused about the logic related to
$dir_has_slash. Why do we need that? Wouldn't it be more simple to remove the trailing slash once (also in the main method) and drop the if(), few lines below:if ($depth == 0 && $dir_has_slash) {...? Or I'm missing something.This also looks like a part that should run only once. It seems that on every recursion the result of
$default_nomaksis the same. It doesn't depend on the recursion depth. We can move it in the main method and pass it to the protected method, or add it as a new entry in$options, as 'default_nomaks'.This check is also needed only for the top directory because the subsequent directories are checked again with
is_dir()few lines below:if ($options['recurse'] && is_dir($uri)) {. That means every sub-dir is checked twice. We can move it in the main method.If the trim of trailing slash works (see above), we can drop this.
Comment #53
kim.pepperThanks @claudiu.cristea for a great review as always.
Re: #50 @martin107 the deprecation messages on file_destination() and file_unmanaged_prepare() aren't in this patch??
Comment #54
kim.pepperComment #56
martin107 commented@kim.pepper - Sorry I did not mean to give you grief.
As I visually scanned the patch, my brain flagged the imperfections that phpcs would spot and then I blindly reported the stuff incorrectly.
by way of getting right with the universe .. here is the change.
Comment #58
kim.pepperNo grief taken. :-) I was just a bit confused that's all. I usually run phpcs across changed files before posting patches, and I guess this wasn't picked up.
Re #52.2 Looks like rtrim is too aggressive. I've removed it altogether to see what breaks.
Comment #60
kim.pepperWe still need to check if the path ends with a slash when creating the URI.
Comment #61
jibranThese are not the same. I don't know we can document parent exception like that.
This not thrown anywhere in this function. Am I missing something?
Comment #62
kim.pepperFixes for #61 to specify the exact exception.
Also removed duplicate docblock comments in doScanDirectory() to refer to scanDirectory().
Comment #64
pguillard commentedHere is a a rerolled-patch
Comment #65
pguillard commentedComment #67
kim.pepperI couldn't work out what changed in #64 so I re-rolled #62 again.
Comment #68
kim.pepperLooks like we needed to convert a usage of file_stream_wrapper_uri_normalize().
Comment #70
kim.pepperFixed a missing import in install.inc
Comment #71
darrenwh commentedHiding old patches
Comment #72
darrenwh commentedComment #73
darrenwh commentedThis method call (scanDirectory) throws an exception, should it be caught here and in all other cases where it's called?
Comment #74
kim.pepperWhy should it catch the exception in all places it is used?
Comment #75
kim.pepperIn drupal_get_database_types() we are scanning core/lib/Drupal/Core/Database/Driver which we know exists, and checking if the directory exists for drivers/lib/Drupal/Driver/Database, so it's not needed.
In CssCollectionOptimizer and JsCollectionOptimizer we are checking if the directory exists before scanning. So again, it's not needed.
Putting back to Needs Review for other reviewers.
Comment #76
yogeshmpawarComment #77
yogeshmpawarResolved one coding standard issue & added an interdiff as well.
Comment #78
kim.pepperFixes missing import, and removes git merge cruft.
Comment #79
berdirI'm not *completely* convinced that requiring a valid directory is a good thing, results in a ton of extra checks.
this needs a docblock.
Depreacated :)
Comment #80
kim.pepperComment #81
berdir1. Yes, lets see if we can get feedback on that, RTBC otherwise IMHO, splitting the method into a public API and the internal one for the recursion looks much cleaner.
Comment #82
kim.pepperComment #83
andypostReroll and fix message according current core sniffers
Comment #84
kim.pepperBack to RTBC
Comment #85
catchOne minor point, otherwise looks good:
The is_dir() check seems like it should come before the nomask, otherwise we're building up $options['nomask'] for no reason.
Comment #86
kim.pepperFixes #85
Comment #87
darrenwh commentedShould this be a InvalidArgumentException?
https://www.php.net/manual/en/class.invalidargumentexception.php
Comment #88
kim.pepperRe: #87 no, we have a more specific exception we can throw.
Comment #89
kim.pepperGoing to change this back to RTBC to get feedback from @catch
Comment #91
catchCommitted dd90789 and pushed to 8.8.x. Thanks!