Making WordPress.org

Changeset 3164


Ignore:
Timestamp:
05/18/2016 02:12:47 AM (10 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.