The story json generation should skip symlinks.

Created on 23 April 2024, 7 months ago
Updated 16 August 2024, 3 months ago

Problem/Motivation

This may be only an issue for me I get that. I personally make a symlink called components that points to where I have all my source files which includes all my sdc alongside other things I consider source. Anyway when the generator runs it looks in the symlink and doesn't know what to do and throws and error.

Proposed resolution

When scanning directories can we skip anything thats a link.

// scanDirectory in foreach line 85ish
    // Skip if file is a symbolic link
      if (is_link($file)) {
        continue;
      }
✨ Feature request
Status

Active

Version

1.0

Component

Miscellaneous

Created by

πŸ‡ΊπŸ‡ΈUnited States brayn7 Lexington, Ky

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @brayn7
  • Merge request !8Skip symlinks β†’ (Open) created by brayn7
  • Pipeline finished with Success
    7 months ago
    Total: 139s
    #154492
  • πŸ‡ΊπŸ‡ΈUnited States ashooner

    There are a couple of us on Drupal slack that want to get symlinks working for the Storybook module, and this issue came up. Could you clarify your use case? If you are referring to you SDC components via symlink, it seems like you'd want the module to follow symlinks. There are definitely a few parts of the module and underlying libraries that are written to exclude symlinked files. From what I've seen, it looks like on of the iterators being used just doesn't know how to handle symlinked directories, and that's what is causing the error.

    Changing line ~92 to:
    $it = new \RecursiveIteratorIterator($filter, \RecursiveIteratorIterator::LEAVES_ONLY, $flags);

    got past the immediate error, but then you run into the rest of the code not expected symlinked paths.

  • πŸ‡ΊπŸ‡ΈUnited States brayn7 Lexington, Ky

    @ashooner, I have a themes/custom/
    /source/ I have this here bundled with my global styles, js and other assets. This is just subjective but how i would like to structure my theme and not have to have another folder i "theme" in for components. So in that i have a dir 02-components. I symlink that directory to "components" and, its been awhile now, but I was running storybook from the 02-components directory and thats where I wanted to generate the json file as well. Maybe I don't need to do that tho. If you have a suggestion im all ears. Sorry for the late reply.

  • πŸ‡ΊπŸ‡ΈUnited States liberatr Portland, OR

    I came here to request to follow symlinks. In my particular case, we are symlinking a directory of images, for legacy reasons. I discovered either skipping the symlinks or following them would both work. In my case I added the following:

           $flags = \FilesystemIterator::KEY_AS_PATHNAME
             | \FilesystemIterator::CURRENT_AS_FILEINFO
             | \FilesystemIterator::SKIP_DOTS
    +       | \FilesystemIterator::FOLLOW_SYMLINKS;
    
  • πŸ‡­πŸ‡ΊHungary Sweetchuck Budapest

    +1 for follow symlinks. For different reasons.

    Composer has a feature, called repository type "path".
    https://getcomposer.org/doc/05-repositories.md#path

    It is a very handy feature for local development, and it also uses symlinks. (That is the best part).
    So, the whole Drupal module is symlinked into DRUPAL_ROOT/modules/contrib/*

    Currently the code throws an "UnprocessableEntityHttpException" exception with message: "Invalid template path for the stories "%s"."
    Even if the module does not contain any SDC component or *.stories.twig file.
    For example "admin_toolbar" module, just because it is the first in alphabetical order.

  • πŸ‡­πŸ‡ΊHungary Sweetchuck Budapest

    I am not fully aware of the requirements, but I think the current *.stories.twig files discovery is a little bit over complicated in the \Drupal\storybook\Drush\Commands\StorybookCommands::generateAllStories command.

    Current solution. Which uses a custom RegexRecursiveFilterIterator.

      $flags = \FilesystemIterator::KEY_AS_PATHNAME
        | \FilesystemIterator::CURRENT_AS_FILEINFO
        | \FilesystemIterator::SKIP_DOTS;
      $directory_iterator = new \RecursiveDirectoryIterator($directory, $flags);
      // Detect "my_component.component.yml".
      $regex = '/^([a-z0-9_-])+\.stories\.twig$/i';
      $filter = new RegexRecursiveFilterIterator($directory_iterator, $regex);
      $it = new \RecursiveIteratorIterator($filter, \RecursiveIteratorIterator::LEAVES_ONLY, $flags);
    

    could be replaced with this:

      $it = (new Finder())
        ->in($directory)
        ->files()
        ->name('/^([a-z0-9_-])+\.stories\.twig$/i');
    

    In a D10.3 project
    composer why 'symfony/finder'

    ...
    drush/drush                     12.5.3  requires  symfony/finder (^6)
    ...
    

    The code above works for me for symlinks as well. See my previous comment.

    I think the code could be simplified even more. (I haven't tried it)

        $template_files = new Finder();
        foreach (['profiles', 'modules', 'themes'] as $directory) {
          $template_files->append(
            (new Finder())
              ->in($directory)
              ->files()
              ->name('/^([a-z0-9_-])+\.stories\.twig$/i'),
          );
        }
    
        foreach ($template_files as $template_file) {
          $this->generateStoriesForTemplate($template_file->getPathname(), $options);
        }
    
  • πŸ‡­πŸ‡ΊHungary Sweetchuck Budapest

    Why is the i (case-insensitive matching) modifier is there in the file selector regexp?
    /^([a-z0-9_-])+\.stories\.twig$/i
    https://git.drupalcode.org/project/storybook/-/blob/360a91f491f4015f7266...

    It matches to a file name like this as well: fooBar.stORies.tWIg
    Then the validateTemplatePath will throw an exception.
    But it will allow this one: fooBar.stories.twig

    Is this the desired behavior?

Production build 0.71.5 2024