Skip to content

Commit 5a9b94d

Browse files
committed
Rework requirements checks
This breaks the checks for requirements away from the notices, as well as introducing more robust handling for different requirement constraints (<, <=, >, >=, =, ==, !=). Signed-off-by: Ryan McCue <me@ryanmccue.info>
1 parent e90e8cc commit 5a9b94d

File tree

3 files changed

+119
-50
lines changed

3 files changed

+119
-50
lines changed

inc/packages/admin/info.php

Lines changed: 14 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace FAIR\Packages\Admin\Info;
99

10+
use FAIR\Packages;
1011
use FAIR\Packages\Admin;
1112
use FAIR\Packages\MetadataDocument;
1213
use FAIR\Packages\ReleaseDocument;
@@ -165,7 +166,7 @@ function render( MetadataDocument $doc, string $tab, string $section ) {
165166

166167
<div id="section-holder">
167168
<?php
168-
check_requirements( $latest );
169+
add_requirement_notices( $latest );
169170
foreach ( $sections as $section_id => $content ) {
170171
$prepared = sanitize_html( $content );
171172
$prepared = links_add_target( $prepared, '_blank' );
@@ -324,53 +325,19 @@ function render_fyi( MetadataDocument $doc, ReleaseDocument $release ) : void {
324325
}
325326

326327
/**
327-
* Get version requirements.
328+
* Check requirements, and add notices if not met.
328329
*
329330
* @param ReleaseDocument $release Release document.
330-
*
331-
* @return array
331+
* @return void
332332
*/
333-
function version_requirements( ReleaseDocument $release ) {
334-
$required_versions = [];
335-
foreach ( $release->requires as $pkg => $vers ) {
336-
$vers = preg_replace( '/^[^0-9]+/', '', $vers );
337-
if ( $pkg === 'env:php' ) {
338-
$required_versions['requires_php'] = $vers;
339-
}
340-
if ( $pkg === 'env:wp' ) {
341-
$required_versions['requires_wp'] = $vers;
342-
}
343-
}
344-
foreach ( $release->suggests as $pkg => $vers ) {
345-
$vers = preg_replace( '/^[^0-9]+/', '', $vers );
346-
if ( $pkg === 'env:wp' ) {
347-
$required_versions['tested_to'] = $vers;
348-
}
333+
function add_requirement_notices( ReleaseDocument $release ) : void {
334+
$unmet_requires = Packages\get_unmet_requirements( (array) $release->requires );
335+
$unmet_suggests = Packages\get_unmet_requirements( (array) $release->suggests );
336+
if ( empty( $unmet_requires ) && empty( $unmet_suggests ) ) {
337+
return;
349338
}
350339

351-
return $required_versions;
352-
}
353-
354-
/**
355-
* Check requirements.
356-
*
357-
* @param ReleaseDocument $release Release document.
358-
*
359-
* @return bool
360-
*/
361-
function check_requirements( ReleaseDocument $release ) {
362-
$required_versions = version_requirements( $release );
363-
$requires_php = $required_versions['requires_php'] ?? null;
364-
$requires_wp = $required_versions['requires_wp'] ?? null;
365-
$tested_to = $required_versions['tested_to'] ?? null;
366-
367-
$compatible_php = is_php_version_compatible( $requires_php );
368-
$compatible_wp = is_wp_version_compatible( $requires_wp );
369-
370-
// Set to true if using a development release.
371-
$tested_wp = (bool) preg_match( '/alpha|beta|RC/', get_bloginfo( 'version' ) ) ?? ( empty( $tested_to ) || version_compare( get_bloginfo( 'version' ), $tested_to, '<=' ) );
372-
373-
if ( ! $compatible_php ) {
340+
if ( isset( $unmet_requires['env:php'] ) ) {
374341
$compatible_php_notice_message = '<p>';
375342
$compatible_php_notice_message .= __( '<strong>Error:</strong> This plugin <strong>requires a newer version of PHP</strong>.', 'fair' );
376343

@@ -394,15 +361,16 @@ function check_requirements( ReleaseDocument $release ) {
394361
);
395362
}
396363

397-
if ( ! $tested_wp ) {
364+
$is_dev = (bool) preg_match( '/alpha|beta|RC/', get_bloginfo( 'version' ) );
365+
if ( isset( $unmet_suggests['env:wp'] ) && ! $is_dev ) {
398366
wp_admin_notice(
399367
__( '<strong>Warning:</strong> This plugin <strong>has not been tested</strong> with your current version of WordPress.', 'fair' ),
400368
[
401369
'type' => 'warning',
402370
'additional_classes' => [ 'notice-alt' ],
403371
]
404372
);
405-
} elseif ( ! $compatible_wp ) {
373+
} elseif ( isset( $unmet_requires['env:wp']) ) {
406374
$compatible_wp_notice_message = __( '<strong>Error:</strong> This plugin <strong>requires a newer version of WordPress</strong>.', 'fair' );
407375
if ( current_user_can( 'update_core' ) ) {
408376
$compatible_wp_notice_message .= sprintf(
@@ -420,8 +388,6 @@ function check_requirements( ReleaseDocument $release ) {
420388
]
421389
);
422390
}
423-
424-
return $compatible_php && $compatible_wp && $tested_to;
425391
}
426392

427393
/**
@@ -439,7 +405,7 @@ function get_action_button( MetadataDocument $doc, ReleaseDocument $release ) {
439405
}
440406

441407
// Do we actually meet the requirements?
442-
$compatible = check_requirements( $release );
408+
$compatible = Packages\check_requirements( $release );
443409

444410
$status = 'install'; // todo.
445411
switch ( $status ) {

inc/packages/namespace.php

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,4 +322,107 @@ function pick_artifact_by_lang( array $artifacts, ?string $locale = null ) {
322322
return apply_filters( 'fair.packages.pick_artifact_by_lang', $selected, $artifacts, $locale, $langs );
323323
}
324324

325+
/**
326+
* Get version requirements.
327+
*
328+
* @param ReleaseDocument $release Release document.
329+
*
330+
* @return array
331+
*/
332+
function version_requirements( ReleaseDocument $release ) {
333+
$required_versions = [];
334+
foreach ( $release->requires as $pkg => $vers ) {
335+
$vers = preg_replace( '/^[^0-9]+/', '', $vers );
336+
if ( $pkg === 'env:php' ) {
337+
$required_versions['requires_php'] = $vers;
338+
}
339+
if ( $pkg === 'env:wp' ) {
340+
$required_versions['requires_wp'] = $vers;
341+
}
342+
}
343+
foreach ( $release->suggests as $pkg => $vers ) {
344+
$vers = preg_replace( '/^[^0-9]+/', '', $vers );
345+
if ( $pkg === 'env:wp' ) {
346+
$required_versions['tested_to'] = $vers;
347+
}
348+
}
349+
350+
return $required_versions;
351+
}
352+
353+
/**
354+
* Get unmet requirements.
355+
*
356+
* @param array $requirements Requirements to check. Map of package names to requirement strings.
357+
* @return array Map of package names to unmet requirements.
358+
*/
359+
function get_unmet_requirements( array $requirements ) : array {
360+
$unmet = [];
361+
foreach ( $requirements as $pkg => $req ) {
362+
$req = trim( $req );
363+
$comp_spn = strspn( $req, '<>=!' );
364+
if ( $comp_spn === 0 ) {
365+
// Invalid requirement, for now.
366+
continue;
367+
}
368+
369+
$comp = trim( substr( $req, 0, $comp_spn ) );
370+
$ver = trim( substr( $req, $comp_spn ) );
371+
372+
switch ( true ) {
373+
case $pkg === 'env:wp':
374+
// From is_wp_version_compatible()
375+
// We use our own copy to allow passing $comp
376+
if (
377+
defined( 'WP_RUN_CORE_TESTS' )
378+
&& WP_RUN_CORE_TESTS
379+
&& isset( $GLOBALS['_wp_tests_wp_version'] )
380+
) {
381+
$wp_version = $GLOBALS['_wp_tests_wp_version'];
382+
} else {
383+
$wp_version = wp_get_wp_version();
384+
}
385+
386+
$valid = version_compare( $wp_version, $ver, $comp );
387+
if ( ! $valid ) {
388+
$unmet[ $pkg ] = $req;
389+
}
390+
break;
391+
392+
case $pkg === 'env:php':
393+
$valid = version_compare( PHP_VERSION, $ver, $comp );
394+
if ( ! $valid ) {
395+
$unmet[ $pkg ] = $req;
396+
}
397+
break;
398+
399+
case str_starts_with( $pkg, 'env:php-' ):
400+
// todo: check extensions.
401+
break;
402+
403+
case str_starts_with( $pkg, 'env:' ):
404+
// todo: check other env, or fail.
405+
break;
406+
407+
default:
408+
// todo: check packages.
409+
break;
410+
}
411+
}
412+
413+
return $unmet;
414+
}
415+
416+
/**
417+
* Check if a release meets the requirements.
418+
*
419+
* @param ReleaseDocument $release Release document.
420+
*
421+
* @return bool True if the release meets the requirements, false otherwise.
422+
*/
423+
function check_requirements( ReleaseDocument $release ) {
424+
$requires = get_unmet_requirements( (array) $release->requires );
425+
return empty( $requires );
426+
}
427+
325428
// phpcs:enable

inc/updater/class-updater.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
use const FAIR\Packages\SERVICE_ID;
1111

12-
use function FAIR\Packages\Admin\Info\check_requirements;
12+
use FAIR\Packages;
1313
use function FAIR\Packages\fetch_metadata_doc;
1414
use function FAIR\Packages\fetch_package_metadata;
1515
use function FAIR\Packages\get_did_document;
@@ -314,7 +314,7 @@ public function update_site_transient( $transient ) {
314314
$rel_path = plugin_basename( $this->filepath );
315315
$response = $this->get_update_data();
316316
$response = 'plugin' === $this->type ? (object) $response : $response;
317-
$is_compatible = check_requirements( $this->release );
317+
$is_compatible = Packages\check_requirements( $this->release );
318318

319319
if ( $is_compatible && version_compare( $this->release->version, $this->local_version, '>' ) ) {
320320
$transient->response[ $rel_path ] = $response;

0 commit comments

Comments
 (0)