WordPress.org

Making WordPress.org

Changeset 3164


Ignore:
Timestamp:
05/18/2016 02:12:47 AM (4 years ago)
Author:
dd32
Message:

Plugin Directory: Imports: Many fixes to the import processes, optimizations, bugfixes, etc.

See #1584

Location:
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/bin/import-plugin.php

    r2649 r3164  
    66    die();
    77}
     8
     9ob_start();
    810
    911$opts = getopt( '', array( 'url:', 'abspath:', 'plugin:' ) );
     
    5052try {
    5153    $importer = new CLI\Import;
    52     $importer->import( $plugin_slug );
     54    $importer->import_from_svn( $plugin_slug );
    5355    echo "OK\n";
    5456} catch( \Exception $e ) {
    5557    echo "Failed.\n";
    56     fwrite( STDERR, "Plugin Import Failed: " . $e->getMessage() . "\n" );
     58    fwrite( STDERR, "[{$plugin_slug}] Plugin Import Failed: " . $e->getMessage() . "\n" );
    5759    exit(1);
    5860}
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/cli/class-import.php

    r3129 r3164  
    77use WordPressdotorg\Plugin_Directory\Tools\Filesystem;
    88use WordPressdotorg\Plugin_Directory\Tools\SVN;
     9use Exception;
    910
    1011/**
     
    4748     * @param string $plugin_slug The slug of the plugin to import.
    4849     */
    49     public function import( $plugin_slug ) {
     50    public function import_from_svn( $plugin_slug ) {
     51        global $wpdb;
     52
    5053        $plugin = Plugin_Directory::get_plugin_post( $plugin_slug );
    5154        if ( ! $plugin ) {
    52 // TODO         throw new \Exception( "Unknown Plugin" );
     55// TODO         throw new Exception( "Unknown Plugin" );
    5356        }
    5457
    5558        $data = $this->export_and_parse_plugin( $plugin_slug );
    5659
    57         if ( ! $plugin ) {
    58             global $wpdb;
    59             // TODO: During development while the bbPress variant is still running, we'll pull details from it and allow importing of any plugin.
    60             $author = $wpdb->get_var( $wpdb->prepare( 'SELECT topic_poster FROM ' . PLUGINS_TABLE_PREFIX . 'topics WHERE topic_slug = %s', $plugin_slug ) );
    61             if ( ! $author ) {
    62                 throw new \Exception( "Unknown Plugin" );
    63             }
     60    // TODO: During development while the bbPress variant is still running, we'll pull details from it and allow importing of any plugin.
     61        $topic = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM ' . PLUGINS_TABLE_PREFIX . 'topics WHERE topic_slug = %s', $plugin_slug ) );
     62
     63        if ( ! $plugin && ! $topic ) {
     64            throw new Exception( "Unknown Plugin" );
     65        }
     66
     67        // TODO: During development we're just going to import status from bbPress.
     68        $status = 'publish';
     69        if ( 2 == $topic->topic_open ) {
     70            $status = 'approved';
     71        } elseif ( 2 == $topic->forum_id ) {
     72            $status = 'pending';
     73        } elseif ( 4 == $topic->forum_id || 'rejected-' == substr( $topic->topic_slug, 0, 9 ) ) {
     74            $status = 'rejected';
     75        } elseif ( 1 == $topic->forum_id && 0 == $topic->topic_open ) {
     76            $status = 'closed';
     77        } elseif ( 3 == $topic->topic_open ) {
     78            $status = 'disabled';
     79        }
     80
     81        if ( ! $plugin ) {         
    6482            $plugin = Plugin_Directory::create_plugin_post( array(
    6583                'slug' => $plugin_slug,
    66                 'status' => 'publish', // If we're importing it on the CLI, and it didn't exist, assume it's published
    67                 'author' => $author
     84                'status' => $status,
     85                'author' => $topic->topic_poster,
     86                'post_date_gmt' => $topic->topic_start_time,
     87                'post_date' => $topic->topic_start_time,
     88                'post_modified' => $topic->topic_time,
     89                'post_modified_gmt' => $topic->topic_time,
    6890            ) );
    6991        }
     
    7294        $assets = $data['assets'];
    7395        $headers = $data['plugin_headers'];
     96        $stable_tag = $data['stable_tag'];
    7497        $tagged_versions = $data['tagged_versions'];
    7598
    7699        $content = '';
    77         foreach ( $readme->sections as $section => $section_content ) {
    78             $content .= "\n\n<!--section={$section}-->\n{$section_content}";
     100        if ( $readme->sections ) {
     101            foreach ( $readme->sections as $section => $section_content ) {
     102                $content .= "\n\n<!--section={$section}-->\n{$section_content}";
     103            }
     104        } elseif ( !empty( $headers->Description ) ) {
     105            $content = "<!--section=description-->\n{$headers->Description}";
    79106        }
    80107
    81108        // Fallback to the plugin title if the readme didn't contain it.
    82         $plugin->post_title   = trim( $readme->name ) ?: strip_tags( $headers->Name );
    83         $plugin->post_content = trim( $content );
    84         $plugin->post_excerpt = trim( $readme->short_description );
     109        $plugin->post_title   = trim( $readme->name ) ?: strip_tags( $headers->Name ) ?: $plugin->post_title;
     110        $plugin->post_content = trim( $content ) ?: $plugin->post_content;
     111        $plugin->post_excerpt = trim( $readme->short_description ) ?: $headers->Description ?: $plugin->post_excerpt;
     112
     113        $plugin->post_date     = $topic->topic_start_time;
     114        $plugin->post_date_gmt = $topic->topic_start_time;
     115        $plugin->override_modified_date = true;
     116        $plugin->post_modified     = $topic->topic_time;
     117        $plugin->post_modified_gmt = $topic->topic_time;
     118
     119        $plugin->post_status = $status;
     120        if ( ! $plugin->post_title ) {
     121            $plugin->post_title = $topic->topic_title;
     122        }
    85123
    86124        // Bump last updated if the version has changed.
    87         if ( $headers->Version != get_post_meta( $plugin->ID, 'version', true ) ) {
     125        if ( !isset( $headers->Version ) || $headers->Version != get_post_meta( $plugin->ID, 'version', true ) ) {
    88126            $plugin->post_modified = $plugin->post_modified_gmt = current_time( 'mysql' );
    89127        }
    90128
     129        add_filter( 'wp_insert_post_data', array( $this, 'filter_wp_insert_post_data' ), 10, 2 );
    91130        wp_update_post( $plugin );
     131        remove_filter( 'wp_insert_post_data', array( $this, 'filter_wp_insert_post_data' ) );
    92132
    93133        foreach ( $this->readme_fields as $readme_field ) {
     
    96136                continue;
    97137            }
    98             update_post_meta( $plugin->ID, $readme_field, wp_slash( $readme->$readme_field ) );
    99         }
     138
     139            if ( 'stable_tag' == $readme_field ) {
     140                // The stable_tag needs to come from the trunk readme at all times.
     141                $value = $stable_tag;
     142            } else {
     143                $value = $readme->$readme_field;
     144            }
     145
     146            update_post_meta( $plugin->ID, $readme_field, wp_slash( $value ) );
     147        }
     148
    100149        foreach ( $this->plugin_headers as $plugin_header => $meta_field ) {
    101             update_post_meta( $plugin->ID, $meta_field, wp_slash( $headers->$plugin_header ) );
     150            update_post_meta( $plugin->ID, $meta_field, ( isset( $headers->$plugin_header ) ? wp_slash( $headers->$plugin_header ) : '' ) );
    102151        }
    103152
     
    141190     *
    142191     * @return array {
    143      *   'readme', 'trunk_readme', 'tmp_dir', 'plugin_headers', 'assets'
     192     *   'readme', 'stable_tag', 'plugin_headers', 'assets', 'tagged_versions'
    144193     * }
    145194     */
     
    147196        $tmp_dir = Filesystem::temp_directory( "process-{$plugin_slug}" );
    148197
    149         $svn_export = SVN::export( self::PLUGIN_SVN_BASE . "/{$plugin_slug}/trunk", $tmp_dir . '/trunk', array( 'ignore-externals' ) );
    150         if ( ! $svn_export['result'] || empty( $svn_export['revision'] ) ) {
    151             throw new \Exception( "Could not create SVN export." . implode( ' ', reset( $svn_export['errors'] ) ) );
    152         }
    153         $trunk_revision = $svn_export['revision'];
    154 
    155         $trunk_readme = $this->find_readme_file( $tmp_dir . '/trunk' );
    156         if ( ! $trunk_readme ) {
    157             throw new \Exception( "Could not locate a trunk readme" );
    158         }
    159         $trunk_readme = new Readme_Parser( $trunk_readme );
    160 
    161         if ( $trunk_readme->stable_tag == 'trunk' || empty( $trunk_readme->stable_tag ) ) {
    162             $readme = $trunk_readme;
    163             $stable = 'trunk';
    164             $stable_revision = $trunk_revision;
     198        // Find the trunk readme file, list remotely to avoid checking out the entire directory.
     199        $trunk_files = SVN::ls( self::PLUGIN_SVN_BASE . "/{$plugin_slug}/trunk" );
     200        if ( ! $trunk_files ) {
     201            throw new Exception( 'Plugin has no files in trunk.' );
     202        }
     203
     204        // A plugin historically doesn't have to have a readme.
     205        $trunk_readme_files = preg_grep( '!^readme.(txt|md)$!i', $trunk_files );
     206        if ( $trunk_readme_files ) {
     207            $trunk_readme_file = reset( $trunk_readme_files );
     208            foreach ( $trunk_readme_files as $f ) {
     209                if ( '.txt' == strtolower( substr( $f, -4 ) ) ) {
     210                    $trunk_readme_file = $f;
     211                    break;
     212                }
     213            }
     214
     215            $trunk_readme_file = self::PLUGIN_SVN_BASE . "/{$plugin_slug}/trunk/{$trunk_readme_file}";
     216            $trunk_readme = new Readme_Parser( $trunk_readme_file );
     217
     218            $stable_tag = $trunk_readme->stable_tag;
    165219        } else {
    166             // There's a chance that the stable_tag will not actually exist, we have to fallback to trunk in those cases and avoid exiting here.
    167             $stable_tag = preg_replace( '![^a-z0-9-_.]!i', '', $trunk_readme->stable_tag );
    168             $svn_export = SVN::export( self::PLUGIN_SVN_BASE . "/{$plugin_slug}/tags/{$stable_tag}",  $tmp_dir . '/stable', array( 'ignore-externals' ) );
    169 
    170             $stable_readme = $svn_export['result'] ? $this->find_readme_file( $tmp_dir . '/stable' ) : false;
    171             if ( $stable_readme ) {
    172                 $readme = $stable_readme = new Readme_Parser( $stable_readme );
    173                 $stable = 'stable';
    174                 $stable_revision = $svn_export['revision'];
     220            $stable_tag = 'trunk';
     221        }
     222
     223        $exported = false;
     224        if ( $stable_tag && 'trunk' != $stable_tag ) {
     225            $svn_export = SVN::export(
     226                self::PLUGIN_SVN_BASE . "/{$plugin_slug}/tags/{$stable_tag}",
     227                $tmp_dir . '/export',
     228                array(
     229                    'ignore-externals',
     230                    'depth' => 'files'
     231                )
     232            );
     233            if ( $svn_export['result'] && false !== $this->find_readme_file( $tmp_dir . '/export' ) ) {
     234                $exported = true;
    175235            } else {
    176                 // Trunk is stable!
    177                 $readme = $trunk_readme;
    178                 $stable = 'trunk';
    179                 $stable_revision = $trunk_revision;
    180             }
    181         }
    182 
    183         $plugin_headers = $this->find_plugin_headers( "$tmp_dir/$stable" );
     236                // Clear out any files that exist in the export.
     237                Filesystem::rmdir( $tmp_dir . '/export' );
     238            }
     239        }
     240        if ( ! $exported ) {
     241            $stable_tag = 'trunk';
     242            // Either stable_tag = trunk, or the stable_tag tag didn't exist.
     243            $svn_export = SVN::export(
     244                self::PLUGIN_SVN_BASE . "/{$plugin_slug}/trunk",
     245                $tmp_dir . '/export',
     246                array(
     247                    'ignore-externals',
     248                    'depth' => 'files' // Only export the root files, we don't need the rest to read the plugin headers/screenshots
     249                )
     250            );
     251            if ( ! $svn_export['result'] || empty( $svn_export['revision'] ) ) {
     252                throw new Exception( 'Could not create SVN export: ' . implode( ' ', reset( $svn_export['errors'] ) ) );
     253            }
     254        }
     255
     256        // The readme may not actually exist, but that's okay.
     257        $readme = $this->find_readme_file( $tmp_dir . '/export' );
     258        $readme = new Readme_Parser( $readme );
     259
     260        // There must be valid plugin headers though.
     261        $plugin_headers = $this->find_plugin_headers( "$tmp_dir/export" );
     262        if ( ! $plugin_headers ) {
     263            throw new Exception( 'Could not find the plugin headers.' );
     264        }
    184265
    185266        // Now we look in the /assets/ folder for banners, screenshots, and icons.
     
    201282        }
    202283
    203         $tagged_versions = SVN::ls( "https://plugins.svn.wordpress.org/{$plugin_slug}/tags/" );
     284        $tagged_versions = SVN::ls( "https://plugins.svn.wordpress.org/{$plugin_slug}/tags/" ) ?: array();
    204285        $tagged_versions = array_map( function( $item ) {
    205286            return rtrim( $item, '/' );
     
    207288
    208289        // Find screenshots in the stable plugin folder (but don't overwrite /assets/)
    209         foreach ( Filesystem::list_files( "$tmp_dir/$stable/", false /* non-recursive */, '!^screenshot-\d+\.(jpeg|jpg|png|gif)$!' ) as $plugin_screenshot ) {
     290        foreach ( Filesystem::list_files( "$tmp_dir/export/", false /* non-recursive */, '!^screenshot-\d+\.(jpeg|jpg|png|gif)$!' ) as $plugin_screenshot ) {
    210291            $filename = basename( $plugin_screenshot );
    211292            $screenshot_id = substr( $filename, strpos( $filename, '-' ) + 1 );
     
    219300            $assets['screenshot'][ $filename ] = array(
    220301                'filename' => $filename,
    221                 'revision' => $stable_revision,
     302                'revision' => $svn_export['revision'],
    222303                'resolution' => $screenshot_id,
    223304                'location' => 'plugin',
     
    225306        }
    226307
    227         return compact( 'readme', 'trunk_readme', 'tmp_dir', 'plugin_headers', 'assets', 'tagged_versions' );
     308        return compact( 'readme', 'stable_tag', 'tmp_dir', 'plugin_headers', 'assets', 'tagged_versions' );
     309    }
     310
     311    /**
     312     * Filters `wp_insert_post()` to allow a custom modified date to be specified.
     313     *
     314     * @param array $data    The data to be inserted into the database.
     315     * @param array $postarr The raw data passed to `wp_insert_post()`.
     316     *
     317     * @return array The data to insert into the database.
     318     */
     319    public function filter_wp_insert_post_data( $data, $postarr ) {
     320        if ( !empty( $postarr['override_modified_date'] ) ) {
     321            $data['post_modified']     = $postarr['post_modified'];
     322            $data['post_modified_gmt'] = $postarr['post_modified_gmt'];
     323        }
     324        return $data;
    228325    }
    229326
     
    260357        $files = Filesystem::list_files( $directory, false, '!\.php$!i' );
    261358
     359        if ( ! function_exists( 'get_plugin_data' ) ) {
     360            require ABSPATH . 'wp-admin/includes/plugin.php';
     361        }
     362
     363        /*
     364         * Sometimes plugins have multiple files which we detect as a plugin based on the headers.
     365         * We'll return immediately if the file has a `Plugin Name:` header, otherwise
     366         * simply return the last set of headers we come across.
     367         */
     368        $possible_headers = false;
    262369        foreach ( $files as $file ) {
    263370            $data = get_plugin_data( $file, false, false );
    264371            if ( array_filter( $data ) ) {
    265                 return (object) $data;
    266             }
     372                if ( $data['Name'] ) {
     373                    return (object) $data;
     374                } else {
     375                    $possible_headers = (object) $data;
     376                }
     377            }
     378        }
     379
     380        if ( $possible_headers ) {
     381            return $possible_headers;
    267382        }
    268383
Note: See TracChangeset for help on using the changeset viewer.