Updated: Comment #0

Problem/Motivation

Lots of procedural code in file.inc including drupal_chmod can't be injected into services/ OO code.

  • Increasing test coverage
  • and it could unblock #2304461: KernelTestBaseTNG™ which would make tests run fast, and allow us to write phpunit integration tests (phptests that are not unit tests)
  • exposes and fixes inconsistencies and brittleness in several simpletests as well as the installer

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Task because it exposes and fixes bugs that could be created, but are not yet existing.
Issue priority Major because not a functional bug, but important by community consensous to prevent future bugs.
Disruption None. BC layer left in and slated for removal in Drupal 9.

Could be allowed since major and impact is greater than disruption.

Proposed resolution

Create Drupal\Core\File\FileSystem class, make it the 'file_system' service, and move much of file.inc into methods on it. Leave file.inc methods as wrappers to the class and mark as deprecated.

Remaining tasks

  • (done) Write the patch
  • (done) address feedback
  • Reviews

User interface changes

None

API changes

FILE_CHMOD_DIRECTORY and FILE_CHMOD_FILE have been deprecated in favour of \Drupal\Core\File\FileSystem::CHMOD_DIRECTORY and \Drupal\Core\File\FileSystem::CHMOD_FILE

#2033669: Image file objects should be classed

CommentFileSizeAuthor
#65 2050759-file-65.patch64.68 KBtim.plunkett
#65 interdiff.txt5.14 KBtim.plunkett
#60 2050759-file-60.patch64.3 KBtim.plunkett
#60 interdiff.txt624 bytestim.plunkett
#58 interdiff.txt38.21 KBtim.plunkett
#58 2050759-file-58.patch64.25 KBtim.plunkett
#53 2050759-file-53.patch48.01 KBtim.plunkett
#52 2050759-file-52.patch68.13 KBtim.plunkett
#52 interdiff.txt1.03 KBtim.plunkett
#49 interdiff.txt3.67 KBtim.plunkett
#49 2050759-file-49.patch60.33 KBtim.plunkett
#47 interdiff.txt787 bytestim.plunkett
#47 2050759-file-47.patch58.57 KBtim.plunkett
#45 interdiff.txt3.66 KBtim.plunkett
#45 2050759-file-45.patch58.38 KBtim.plunkett
#41 interdiff.txt614 bytesfietserwin
#41 move_drupal_chmod_and-2050759-41.patch44.27 KBfietserwin
#39 interdiff.txt1.06 KBfietserwin
#39 move_drupal_chmod_and-2050759-39.patch43.67 KBfietserwin
#36 interdiff.txt1.79 KBfietserwin
#36 move_drupal_chmod_and-2050759-36.patch43.4 KBfietserwin
#30 2050759-file-30.patch43.26 KBtim.plunkett
#28 interdiff.txt1.11 KBtim.plunkett
#28 2050759-file-28.patch43.11 KBtim.plunkett
#26 interdiff.txt937 bytestim.plunkett
#26 2050759-file-26.patch42 KBtim.plunkett
#22 interdiff.txt517 bytestim.plunkett
#22 2050759-file-21.patch41.09 KBtim.plunkett
#20 interdiff.txt32.68 KBtim.plunkett
#20 2050759-file-20.patch40.73 KBtim.plunkett
#16 2050759-file-16.patch36.15 KBtim.plunkett
#7 file-2050759-7-combined.patch87.92 KBtim.plunkett
#7 file-2050759-7-do-not-test.patch48.83 KBtim.plunkett
#2 file-2050759-2.patch26.99 KBtim.plunkett
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

tim.plunkett’s picture

Issue tags: +Kill includes

.

tim.plunkett’s picture

Status: Active » Needs review
FileSize
26.99 KB

This would be a lot better if #2028109: Convert hook_stream_wrappers() to tagged services. was in. Here's a first pass.

larowlan’s picture

*blink* and you miss it

larowlan’s picture

+++ b/core/lib/Drupal/Core/Utility/File.phpundefined
@@ -0,0 +1,410 @@
+ * @todo.

ha ha

+++ b/core/lib/Drupal/Core/Utility/File.phpundefined
@@ -0,0 +1,410 @@
+        $mode = octdec(config('system.file')->get('chmod.directory'));

I assume we can't register this as a service and inject because we want to keep it static? Should we be using \Drupal::config() instead?

+++ b/core/lib/Drupal/Core/Utility/File.phpundefined
@@ -0,0 +1,410 @@
+    if ($wrapper = file_stream_wrapper_get_instance_by_uri($uri)) {

Can we add a todo for https://drupal.org/node/2028109

+++ b/core/lib/Drupal/Core/Utility/File.phpundefined
@@ -0,0 +1,410 @@
+    $scheme = file_uri_scheme($uri);
+++ b/core/lib/Drupal/Core/Utility/File.phpundefined
@@ -0,0 +1,410 @@
+    if (!file_stream_wrapper_valid_scheme($scheme) && (substr(PHP_OS, 0, 3) == 'WIN')) {
+++ b/core/lib/Drupal/Core/Utility/File.phpundefined
@@ -0,0 +1,410 @@
+    if ($wrapper = file_stream_wrapper_get_instance_by_uri($uri)) {

I'm assuming these are moved in the plugin conversion?

tim.plunkett’s picture

Assigned: Unassigned » tim.plunkett

I'll fix the @todo :)

Drupal::config() is our best bet.

Yes, the rest of that will be plugins once the other issue goes in.

tim.plunkett’s picture

Status: Needs review » Postponed

Not all of the uri/stream functions are going to be straight plugins, they themselves will also need to be wrappers.
I'd like to just postpone this on #2028109: Convert hook_stream_wrappers() to tagged services. for right now.

tim.plunkett’s picture

Just tracking some work, this is what it will look like once the other issue is in.

sun’s picture

I'm very concerned about \Utility turning into a dumping-ground of arbitrary things.

In my mind, \Utility should not contain any classes that depend on other (injected-or-not) services.

So e.g. the utility/helper classes for arrays, array-sorting, string escaping, etc are all fine, because they are self-contained (having only PHP core as a dependency).

But the procedural functions being converted here clearly do not follow that pattern — since they rely and depend on configuration, plugins, and other things, they are part of an own "service", which needs proper dependency injection.

Can we move this code from \Utility into \File, register it as a service and inject the dependencies?


In the end (and hopefully before release), we should ideally consolidate all the file related things into that namespace:

Drupal\Core\File\StreamWrapper\...
Drupal\Core\File\Transfer\...
Drupal\Core\File\FileHandler (or similar; the stuff here)

sun’s picture

Issue summary: View changes
Issue tags: +API clean-up, +@deprecated
tim.plunkett’s picture

Assigned: tim.plunkett » Unassigned
Status: Postponed » Needs work

I don't think we should bother waiting around for #2028109: Convert hook_stream_wrappers() to tagged services.

sun’s picture

larowlan’s picture

Wondering if it makes sense to rewrite file.inc on top of https://github.com/thephpleague/flysystem?
Save reinventing the wheel.

mikeryan’s picture

Anyone working on this? file_unmanaged_copy() right now is unsuitable for use in migration (doesn't work for remote files - see #2244555: Use copy() directly instead of file_unmanaged_copy()), not sure if we should refactor it on its own or as part of this issue.

tim.plunkett’s picture

Assigned: Unassigned » tim.plunkett

I'm working on this.

larowlan’s picture

Thank you

tim.plunkett’s picture

Status: Needs work » Needs review
FileSize
36.15 KB

Here's a fresh start.

fietserwin’s picture

  1. How was decided which functions to move and which not?
  2. How far should this issue go in cleaning up e.g. code style, outdated comments and such?

ad 1)

  • It looks like explicit stream wrapper functions are left in file.inc, but then I don't see a real difference between file_stream_wrapper_get_class() vs file_stream_wrapper_valid_scheme()?
  • file_uri_scheme() vs file_uri_target()
  • ...

ad 2)

  • Some comment lines now exceed the 80 character limit due to the extra indentation.
  • Many parameters and return values are not documented with type information as is now the standard.
  • getDirectoryPath() in method tempnam() can fatal out if the directory does not belong to a LocalStream type stream wrapper.
  • PHP's chmod does support stream wrappers as of PHP 5.4. This part of the documentation for the chmod() method is out dated (after #2107287: PHP 5.4 calls a new stream_metadata() method on stream wrappers not implemented by Drupal).
  • drupal.org is referred to via http, not https.
tim.plunkett’s picture

1) I left the stream wrapper functions that actual need the info/instances of stream wrappers. The rest was moved.
2) I will probably go over this for violations caused by the patch, like 80 chars, but not fixing the rest of it here.

ParisLiakos’s picture

either this or #2043773: Replace php function wrappers in file.inc with a Drupal\Core\File\FileSystem class should be closed..those two issues are very similar

+++ b/core/includes/file.inc
index 0000000..32746e0
--- /dev/null

--- /dev/null
+++ b/core/lib/Drupal/Core/Utility/File.php

i really think Drupal/Core/File is a better namespace for this

tim.plunkett’s picture

FileSize
40.73 KB
32.68 KB

Marked the other issue as a dupe.
Per #8, made this a service. Was able to add tests for chmod and unlink, thanks to vfsStream.

tim.plunkett’s picture

Status: Needs work » Needs review
FileSize
41.09 KB
517 bytes

Forgot to test locally before posting. Missed a service.

fietserwin’s picture

FWIW: adding

  $container
    ->register('file_system', 'Drupal\Core\File\FileSystem')
    ->addArgument(Settings::getInstance())
    ->addArgument((new Drupal\Core\Logger\LoggerChannelFactory())->get('file'));

to function install_begin_request() does make the error go away.

So it is an order problem during installation: the file_system service is not yet there, but already used. Makes me think, can I define a logger that logs to private:\\mylogfile.log and would that give problems here or in #2028109: Convert hook_stream_wrappers() to tagged services.?

tim.plunkett’s picture

Status: Needs work » Needs review
FileSize
42 KB
937 bytes

Services used during the installer need to be registered, so your code is correct.

tim.plunkett’s picture

Status: Needs work » Needs review
FileSize
43.11 KB
1.11 KB

We can't set up the config directories (using the file system) until the container is built.

tim.plunkett’s picture

Assigned: tim.plunkett » Unassigned
Status: Needs work » Needs review
FileSize
43.26 KB

Seems like TestBase is trying to clean up sites/simpletest/* after the container is reset?

Reroll.

tim.plunkett’s picture

Status: Needs work » Needs review

rickvug queued 30: 2050759-file-30.patch for re-testing.

The last submitted patch, 7: file-2050759-7-combined.patch, failed testing.

fietserwin’s picture

FileSize
43.4 KB
1.79 KB

Reroll. interdiff is ot a real interdiff, but a diff of the changes that failed to apply (and that I applied manually).

fietserwin’s picture

Status: Needs work » Needs review
fietserwin’s picture

Status: Needs work » Needs review
FileSize
43.67 KB
1.06 KB

The logger (factory) has a lot of (new) dependencies, but with this change I could reinstall my local test env (via the UI). Let's see if the tests pass.

fietserwin’s picture

FileSize
44.27 KB
614 bytes

It is a hack, but just to see if all failures are a result of the same problem.

Problem: file_uri_scheme() get's called during a web based test setup. Stack trace (not complete):
- WebTestBase::setUp()
- WebTestBase::installParameters()
- drupal_get_database_types()
- file_scan_directory()
- file_stream_wrapper_uri_normalize()
- file_uri_scheme
- \Drupal::service('file_system')
- static::$container->get($id);

And this only to find out if there is more than 1 database driver. I would think that even if there's 1, it won't hurt to select it on the install form (and if it is not there, that web test form fill in handling takes care of fields that are not found on the form).

fietserwin’s picture

Status: Needs work » Needs review
fietserwin’s picture

I give up. It looks like the remaining errors are Drupal test setup specific and I do not have enough knowledge about Drupal testing to solve these remaining errors in an easy way. Someone else who is willing to give it a try?

Remaining failures:
Failure in core\modules\system\src\Tests\Bootstrap\GetFilenameUnitTest.php:
Failure in core\modules\system\src\Tests\Routing\RouteProviderTest.php:
- TestBase::restoreEnvironment()
- file_unmanaged_delete_recursive()
- drupal_rmdir()

TestBase::prepareEnvironment() unsets the container:

    // Ensure there is no service container.
    $this->container = NULL;
    \Drupal::setContainer(NULL);

No idea why, but this probably provokes the errors.

Failure in core\modules\system\src\Tests\DrupalKernel\DrupalKernelTest.php:
- DrupalKernelTest::setUp()
- KernelTestBase::prepareConfigDirectories()
- install_ensure_config_directory()
- file_prepare_directory()
- file_uri_scheme()

I guess that adapting or overriding containerBuild can solve the problems here.

7 Failures in core\modules\simpletest\src\Tests\BrokenSetUpTest.php:
Not sure why, but I guess a similar cause as the first 2.

tim.plunkett’s picture

Status: Needs work » Needs review
FileSize
58.38 KB
3.66 KB

If you do not call parent::setUp(), your test will fail.

There are two problems with that:

BrokenSetUpTest does not call setUp on purpose to show that things are broken.

DrupalKernelTest has this comment:

    // DrupalKernel relies on global $config_directories and requires those
    // directories to exist. Therefore, create the directories, but do not
    // invoke KernelTestBase::setUp(), since that would set up further
    // environment aspects, which would distort this test, because it tests
    // the DrupalKernel (re-)building itself.
tim.plunkett’s picture

Status: Needs work » Needs review
FileSize
58.57 KB
787 bytes

Just to see what happens :D

tim.plunkett’s picture

Status: Needs work » Needs review
FileSize
60.33 KB
3.67 KB

Status: Needs review » Needs work

The last submitted patch, 49: 2050759-file-49.patch, failed testing.

jibran’s picture

+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -1005,13 +1005,28 @@ protected function installParameters() {
+    \Drupal::setContainer($this->originalContainer);
...
+    \Drupal::unsetContainer();

+++ b/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php
@@ -36,6 +36,15 @@ protected function setUp() {
+    \Drupal::setContainer($this->originalContainer);
...
+    \Drupal::unsetContainer();

nice.

tim.plunkett’s picture

Status: Needs work » Needs review
FileSize
1.03 KB
68.13 KB

Wow, BrokenSetUpTest was hard to debug.

Hopefully moving the restoration of the container up a few lines won't break anything.

tim.plunkett’s picture

FileSize
48.01 KB

Okay, so as to not block this on #2363341: Throw exception in Drupal::service() and friends, if container not initialized yet., here's a version of this with those changes stripped out.

jibran’s picture

Issue tags: +Need issue summary update

Thank for removing 2363341 from this patch. We need BE in IS other then that it is RTBC.

dawehner’s picture

  1. +++ b/core/lib/Drupal/Core/File/FileSystem.php
    @@ -0,0 +1,507 @@
    + * Contains \Drupal\Core\File\File.
    ...
    +class FileSystem {
    

    File vs. FileSystem ... did you considered adding an interface ... so would you ever want to replace it?

  2. +++ b/core/lib/Drupal/Core/File/FileSystem.php
    @@ -0,0 +1,507 @@
    +   * @param $uri
    ...
    +   * @param $mode
    

    meh typehinting.

  3. +++ b/core/lib/Drupal/Core/File/FileSystem.php
    @@ -0,0 +1,507 @@
    +  protected function getStreamWrapperClass($scheme) {
    +    return file_stream_wrapper_get_class($scheme);
    ...
    +    return file_stream_wrapper_get_instance_by_scheme($scheme);
    ...
    +    return file_stream_wrapper_get_instance_by_uri($uri);
    

    All of those are deprecated

  4. +++ b/core/lib/Drupal/Core/File/FileSystem.php
    @@ -0,0 +1,507 @@
    +
    +  /**
    +   * Wraps the global Settings singleton.
    +   *
    +   * @codeCoverageIgnore
    +   */
    +  protected function getSetting($name, $default = NULL) {
    +    return $this->settings->get($name, $default);
    +  }
    +
    

    Why do we want to wrap it in the first place?

YesCT’s picture

Priority: Normal » Major
Issue summary: View changes
  • Increasing test coverage
  • and it could unblock #2304461: KernelTestBaseTNG™ which would make tests run fast, and allow us to write phpunit integration tests (phptests that are not unit tests)
  • exposes and fixes inconsistencies and brittleness in several simpletests

adding beta evaluation

YesCT’s picture

Issue summary: View changes

html

tim.plunkett’s picture

Issue summary: View changes
Issue tags: -Need issue summary update
Related issues: +#2304461: KernelTestBaseTNG™
FileSize
64.25 KB
38.21 KB

Addressed the feedback in #55, and updated the issue summary

tim.plunkett’s picture

Issue summary: View changes
Status: Needs work » Needs review
FileSize
624 bytes
64.3 KB

Exposing more issues, this time in the installer: stream_wrapper_manager is registered as needing the module_handler, which doesn't exist in the early installer, but it actually isn't needed at all.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Awesome!

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs change record
  1. +++ b/core/includes/file.inc
    @@ -10,22 +10,11 @@
     /**
    - * Default mode for new directories. See drupal_chmod().
    - */
    -const FILE_CHMOD_DIRECTORY = 0775;
    -
    -/**
    - * Default mode for new files. See drupal_chmod().
    - */
    -const FILE_CHMOD_FILE = 0664;
    

    Lets' deprecate the constants rather than remove them. Let's say they will be removed in D9.

  2. +++ b/core/includes/file.inc
    @@ -129,40 +118,21 @@ function file_stream_wrapper_get_class($scheme) {
    + * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.0.
    + *   Use \Drupal\Core\File\FileSystem::uriScheme().
    

    We should only be saying that new deprecations will be removed in D9. All the deprecations need to be changed.

  3. Missing a CR
tim.plunkett’s picture

Title: Move drupal_chmod and other code in file.inc to a Drupal\Core\Utility\File class » Move drupal_chmod and other code in file.inc to a Drupal\Core\File\FileSystem class
Assigned: Unassigned » tim.plunkett

If we're not going to make any API changes or deprecate anything before D9, why the need for the CR?

I'll fix the other stuff tomorrow, and probably just write the CR as well...

alexpott’s picture

I CRs are valid when we deprecate a load of functions that have been around forever - so people know to use the new functions.

tim.plunkett’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record
FileSize
5.14 KB
64.68 KB
YesCT’s picture

Status: Needs review » Reviewed & tested by the community

looks like you got them all.
no unintended changes either.
change record made.

all feedback from @alexpott addressed.
super.

alexpott’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Fixed

Committed fc63f5e and pushed to 8.0.x. Thanks!

I've updated the beta evaluation and issue summary to reflect the latest changes.

  • alexpott committed fc63f5e on 8.0.x
    Issue #2050759 by tim.plunkett, fietserwin: Move drupal_chmod and other...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.