Merge pull request #680 from sanmadjack/ext_info

Proposed extension info change to allow getting info for unloaded ext…
This commit is contained in:
Shish
2019-09-26 15:37:16 +01:00
committed by GitHub
222 changed files with 3723 additions and 1731 deletions

View File

@@ -22,11 +22,11 @@ $tracer_enabled = constant('TRACE_FILE')!==null;
// load base files
$_tracer->begin("Bootstrap");
$_tracer->begin("Opening files");
$_tracer->begin("Opening core files");
$_shm_files = array_merge(
zglob("core/*.php"),
zglob("core/{".ENABLED_MODS."}/*.php"),
zglob("ext/{".ENABLED_EXTS."}/main.php")
zglob("ext/*/info.php")
);
foreach ($_shm_files as $_shm_filename) {
if (basename($_shm_filename)[0] != "_") {
@@ -37,6 +37,22 @@ unset($_shm_files);
unset($_shm_filename);
$_tracer->end();
$_tracer->begin("Loading extension info");
ExtensionInfo::load_all_extension_info();
Extension::determine_enabled_extensions();
$_tracer->end();
$_tracer->begin("Opening enabled extension files");
$_shm_files = zglob("ext/{".Extension::get_enabled_extensions_as_string()."}/main.php");
foreach ($_shm_files as $_shm_filename) {
if (basename($_shm_filename)[0] != "_") {
require_once $_shm_filename;
}
}
unset($_shm_files);
unset($_shm_filename);
$_tracer->end();
// connect to the database
$_tracer->begin("Connecting to DB");
$database = new Database();
@@ -52,8 +68,7 @@ unset($themelet);
$page = class_exists("CustomPage") ? new CustomPage() : new Page();
$_tracer->end();
// hook up event handlers
$_tracer->begin("Loading extensions");
$_tracer->begin("Loading extensions/event listeners");
_load_event_listeners();
$_tracer->end();

View File

@@ -83,24 +83,24 @@
*/
abstract class Extension
{
/** @var array which DBs this ext supports (blank for 'all') */
protected $db_support = [];
public $key;
/** @var Themelet this theme's Themelet object */
public $theme;
public function __construct()
{
$this->theme = $this->get_theme_object(get_called_class());
}
public $info;
public function is_live(): bool
private static $enabled_extensions = [];
public function __construct($class = null)
{
global $database;
return (
empty($this->db_support) ||
in_array($database->get_driver_name(), $this->db_support)
);
$class = $class ?? get_called_class();
$this->theme = $this->get_theme_object($class);
$this->info = ExtensionInfo::get_for_extension_class($class);
if($this->info===null) {
throw new Exception("Info class not found for extension $class");
}
$this->key = $this->info->key;
}
/**
@@ -128,6 +128,193 @@ abstract class Extension
{
return 50;
}
public static function determine_enabled_extensions()
{
self::$enabled_extensions = [];
foreach(array_merge(ExtensionInfo::get_core_extensions(),
explode(",", EXTRA_EXTS)) as $key) {
$ext = ExtensionInfo::get_by_key($key);
if($ext===null) {
continue;
}
self::$enabled_extensions[] = $ext->key;
if(!empty($ext->dependencies)) {
foreach ($ext->dependencies as $dep) {
self::$enabled_extensions[] = $dep;
}
}
}
}
public static function is_enabled(string $key): ?bool
{
return in_array($key, self::$enabled_extensions);
}
public static function get_enabled_extensions(): array
{
return self::$enabled_extensions;
}
public static function get_enabled_extensions_as_string(): string
{
return implode(",",self::$enabled_extensions);
}
}
abstract class ExtensionInfo
{
// Every credit you get costs us RAM. It stops now.
public const SHISH_NAME = "Shish";
public const SHISH_EMAIL = "webmaster@shishnet.org";
public const SHIMMIE_URL = "http://code.shishnet.org/shimmie2/";
public const SHISH_AUTHOR = [self::SHISH_NAME=>self::SHISH_EMAIL];
public const LICENSE_GPLV2 = "GPLv2";
public const LICENSE_MIT = "MIT";
public const LICENSE_WTFPL = "WTFPL";
public const VISIBLE_ADMIN = "admin";
public const VISIBLE_HIDDEN = "hidden";
private const VALID_VISIBILITY = [self::VISIBLE_ADMIN, self::VISIBLE_HIDDEN];
public $key;
public $core = false;
public $beta = false;
public $name;
public $authors = [];
public $link;
public $license;
public $version;
public $dependencies = [];
public $visibility;
public $description;
public $documentation;
/** @var array which DBs this ext supports (blank for 'all') */
public $db_support = [];
private $supported = null;
private $support_info = null;
public function is_supported(): bool
{
if($this->supported===null) {
$this->check_support();
}
return $this->supported;
}
public function get_support_info(): string
{
if($this->supported===null) {
$this->check_support();
}
return $this->support_info;
}
private static $all_info_by_key = [];
private static $all_info_by_class = [];
private static $core_extensions = [];
protected function __construct()
{
if(empty($this->key)) {
throw new Exception("key field is required");
}
if(empty($this->name)) {
throw new Exception("name field is required for extension $this->key");
}
if(!empty($this->visibility)&&!in_array($this->visibility, self::VALID_VISIBILITY)) {
throw new Exception("Invalid visibility for extension $this->key");
}
if(!is_array($this->db_support)) {
throw new Exception("db_support has to be an array for extension $this->key");
}
if(!is_array($this->authors)) {
throw new Exception("authors has to be an array for extension $this->key");
}
if(!is_array($this->dependencies)) {
throw new Exception("dependencies has to be an array for extension $this->key");
}
}
public function is_enabled(): bool
{
return Extension::is_enabled($this->key);
}
private function check_support()
{
global $database;
$this->support_info = "";
if(!empty($this->db_support)&&!in_array($database->get_driver_name(), $this->db_support)) {
$this->support_info .= "Database not supported. ";
}
// Additional checks here as needed
$this->supported = empty($this->support_info);
}
public static function get_all(): array
{
return array_values(self::$all_info_by_key);
}
public static function get_all_keys(): array
{
return array_keys(self::$all_info_by_key);
}
public static function get_core_extensions(): array
{
return self::$core_extensions;
}
public static function get_by_key(string $key): ?ExtensionInfo
{
if(array_key_exists($key, self::$all_info_by_key)) {
return self::$all_info_by_key[$key];
} else {
return null;
}
}
public static function get_for_extension_class(string $base): ?ExtensionInfo
{
$normal = $base.'Info';
if (array_key_exists($normal, self::$all_info_by_class)) {
return self::$all_info_by_class[$normal];
} else {
return null;
}
}
public static function load_all_extension_info()
{
foreach (get_declared_classes() as $class) {
$rclass = new ReflectionClass($class);
if ($rclass->isAbstract()) {
// don't do anything
} elseif (is_subclass_of($class, "ExtensionInfo")) {
$extension_info = new $class();
if(array_key_exists($extension_info->key, self::$all_info_by_key)) {
throw new Exception("Extension Info $class with key $extension_info->key has already been loaded");
}
self::$all_info_by_key[$extension_info->key] = $extension_info;
self::$all_info_by_class[$class] = $extension_info;
if($extension_info->core===true) {
self::$core_extensions[] = $extension_info->key;
}
}
}
}
}
/**

View File

@@ -468,7 +468,7 @@ class Page
/*** Generate CSS cache files ***/
$css_latest = $config_latest;
$css_files = array_merge(
zglob("ext/{" . ENABLED_EXTS . "}/style.css"),
zglob("ext/{" . Extension::get_enabled_extensions_as_string() . "}/style.css"),
zglob("themes/$theme_name/style.css")
);
foreach ($css_files as $css) {
@@ -499,7 +499,7 @@ class Page
"vendor/bower-asset/js-cookie/src/js.cookie.js",
"ext/handle_static/modernizr-3.3.1.custom.js",
],
zglob("ext/{" . ENABLED_EXTS . "}/script.js"),
zglob("ext/{" . Extension::get_enabled_extensions_as_string() . "}/script.js"),
zglob("themes/$theme_name/script.js")
);
foreach ($js_files as $js) {

View File

@@ -801,4 +801,31 @@ function iterator_map(callable $callback, iterator $iter): Generator
function iterator_map_to_array(callable $callback, iterator $iter): array
{
return iterator_to_array(iterator_map($callback, $iter));
}
function get_class_from_file(string $file): string
{
$fp = fopen($file, 'r');
$class = $buffer = '';
$i = 0;
while (!$class) {
if (feof($fp)) break;
$buffer .= fread($fp, 512);
$tokens = token_get_all($buffer);
if (strpos($buffer, '{') === false) continue;
for (;$i<count($tokens);$i++) {
if ($tokens[$i][0] === T_CLASS) {
for ($j=$i+1;$j<count($tokens);$j++) {
if ($tokens[$j] === '{') {
$class = $tokens[$i+2][1];
}
}
}
}
}
return $class;
}

View File

@@ -44,7 +44,7 @@ function _set_event_listeners(): void
$extension = new $class();
// skip extensions which don't support our current database
if (!$extension->is_live()) {
if (!$extension->info->is_supported()) {
continue;
}
@@ -88,16 +88,6 @@ function _dump_event_listeners(array $event_listeners, string $path): void
file_put_contents($path, $p);
}
function ext_is_live(string $ext_name): bool
{
if (class_exists($ext_name)) {
/** @var Extension $ext */
$ext = new $ext_name();
return $ext->is_live();
}
return false;
}
/** @private */
global $_shm_event_count;
@@ -109,7 +99,7 @@ $_shm_event_count = 0;
function send_event(Event $event): void
{
global $tracer_enabled;
global $_shm_event_listeners, $_shm_event_count, $_tracer;
if (!isset($_shm_event_listeners[get_class($event)])) {
return;

View File

@@ -40,7 +40,6 @@ _d("SEARCH_ACCEL", false); // boolean use search accelerator
_d("WH_SPLITS", 1); // int how many levels of subfolders to put in the warehouse
_d("VERSION", '2.7-beta'); // string shimmie version
_d("TIMEZONE", null); // string timezone
_d("CORE_EXTS", "bbcode,user,mail,upload,image,view,handle_pixel,ext_manager,setup,upgrade,handle_404,handle_static,comment,tag_list,index,tag_edit,alias_editor,media,help_pages,system"); // extensions to always enable
_d("EXTRA_EXTS", ""); // string optional extra extensions
_d("BASE_URL", null); // string force a specific base URL (default is auto-detect)
_d("MIN_PHP_VERSION", '7.1');// string minimum supported PHP version
@@ -53,4 +52,3 @@ _d("ENABLED_MODS", "imageboard");
* directly, only the things they're built from
*/
_d("SCORE_VERSION", 'develop/'.VERSION); // string SCore version
_d("ENABLED_EXTS", CORE_EXTS.",".EXTRA_EXTS);

View File

@@ -454,8 +454,8 @@ function _get_themelet_files(string $_theme): array
$base_themelets[] = 'themes/'.$_theme.'/layout.class.php';
$base_themelets[] = 'themes/'.$_theme.'/themelet.class.php';
$ext_themelets = zglob("ext/{".ENABLED_EXTS."}/theme.php");
$custom_themelets = zglob('themes/'.$_theme.'/{'.ENABLED_EXTS.'}.theme.php');
$ext_themelets = zglob("ext/{".Extension::get_enabled_extensions_as_string()."}/theme.php");
$custom_themelets = zglob('themes/'.$_theme.'/{'.Extension::get_enabled_extensions_as_string().'}.theme.php');
return array_merge($base_themelets, $ext_themelets, $custom_themelets);
}