diff --git a/.idea/nur-ture.iml b/.idea/nur-ture.iml index e8b45d5..0c2e0bf 100644 --- a/.idea/nur-ture.iml +++ b/.idea/nur-ture.iml @@ -6,6 +6,7 @@ + diff --git a/.idea/php.xml b/.idea/php.xml index d4c313d..428268c 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -70,6 +70,23 @@ + + + + + + + + + + + + + + + + + diff --git a/bin/nucache.php b/bin/cachectl.php similarity index 67% rename from bin/nucache.php rename to bin/cachectl.php index edc58ee..48de2bc 100755 --- a/bin/nucache.php +++ b/bin/cachectl.php @@ -2,6 +2,6 @@ args[0] ?? null); $inputname = path::filename($input); diff --git a/composer.json b/composer.json index 4a97753..aee4b34 100644 --- a/composer.json +++ b/composer.json @@ -65,7 +65,8 @@ "autoload": { "psr-4": { "nulib\\": "src", - "nur\\": "nur_src" + "nur\\": "nur_src", + "cli\\": "cli" }, "files": [ "nur_autoload.php" @@ -78,19 +79,13 @@ } }, "bin": [ - "bin/dumpser.php", - "bin/nucache.php", - "bin/csv2xlsx.php", - "bin/json2yml.php", - "bin/yml2json.php", - "bin/sqlite.storage.php", - "bin/mysql.storage.php", - "bin/pgsql.storage.php", + "bin/cachectl.php", + "bin/csv2xlsx.php", "nur_bin/compctl.php", "nur_bin/compdep.php", "nur_bin/datectl.php", "nur_bin/fsvdiff.php", - "nur_bin/cachectl.php", + "nur_bin/legacy-cachectl.php", "nur_bin/ldap-delete.php", "nur_bin/ldap-get-infos.php", "nur_bin/ldap-search.php" diff --git a/composer.lock b/composer.lock index 0e40628..a748a4b 100644 --- a/composer.lock +++ b/composer.lock @@ -86,6 +86,81 @@ ], "time": "2024-11-12T16:29:46+00:00" }, + { + "name": "dflydev/dot-access-data", + "version": "v3.0.3", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.3", + "scrutinizer/ocular": "1.6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Dflydev\\DotAccessData\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.3" + }, + "time": "2024-07-08T12:26:09+00:00" + }, { "name": "doctrine/instantiator", "version": "1.5.0", @@ -217,6 +292,195 @@ }, "time": "2024-11-01T03:51:45+00:00" }, + { + "name": "league/commonmark", + "version": "2.7.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "10732241927d3971d28e7ea7b5712721fa2296ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/10732241927d3971d28e7ea7b5712721fa2296ca", + "reference": "10732241927d3971d28e7ea7b5712721fa2296ca", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "league/config": "^1.1.1", + "php": "^7.4 || ^8.0", + "psr/event-dispatcher": "^1.0", + "symfony/deprecation-contracts": "^2.1 || ^3.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "cebe/markdown": "^1.0", + "commonmark/cmark": "0.31.1", + "commonmark/commonmark.js": "0.31.1", + "composer/package-versions-deprecated": "^1.8", + "embed/embed": "^4.4", + "erusev/parsedown": "^1.0", + "ext-json": "*", + "github/gfm": "0.29.0", + "michelf/php-markdown": "^1.4 || ^2.0", + "nyholm/psr7": "^1.5", + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", + "scrutinizer/ocular": "^1.8.1", + "symfony/finder": "^5.3 | ^6.0 | ^7.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", + "unleashedtech/php-coding-standard": "^3.1.1", + "vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0" + }, + "suggest": { + "symfony/yaml": "v2.3+ required if using the Front Matter extension" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "League\\CommonMark\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)", + "homepage": "https://commonmark.thephpleague.com", + "keywords": [ + "commonmark", + "flavored", + "gfm", + "github", + "github-flavored", + "markdown", + "md", + "parser" + ], + "support": { + "docs": "https://commonmark.thephpleague.com/", + "forum": "https://github.com/thephpleague/commonmark/discussions", + "issues": "https://github.com/thephpleague/commonmark/issues", + "rss": "https://github.com/thephpleague/commonmark/releases.atom", + "source": "https://github.com/thephpleague/commonmark" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/commonmark", + "type": "tidelift" + } + ], + "time": "2025-07-20T12:47:49+00:00" + }, + { + "name": "league/config", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/config.git", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/config/zipball/754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^3.0.1", + "nette/schema": "^1.2", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Config\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Define configuration arrays with strict schemas and access values with dot notation", + "homepage": "https://config.thephpleague.com", + "keywords": [ + "array", + "config", + "configuration", + "dot", + "dot-access", + "nested", + "schema" + ], + "support": { + "docs": "https://config.thephpleague.com/", + "issues": "https://github.com/thephpleague/config/issues", + "rss": "https://github.com/thephpleague/config/releases.atom", + "source": "https://github.com/thephpleague/config" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + } + ], + "time": "2022-12-11T20:36:23+00:00" + }, { "name": "maennchen/zipstream-php", "version": "2.2.6", @@ -404,16 +668,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.13.1", + "version": "1.13.4", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c" + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c", - "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", "shasum": "" }, "require": { @@ -452,7 +716,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.1" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" }, "funding": [ { @@ -460,7 +724,7 @@ "type": "tidelift" } ], - "time": "2025-04-29T12:36:36+00:00" + "time": "2025-08-01T08:46:24+00:00" }, { "name": "myclabs/php-enum", @@ -526,17 +790,165 @@ "time": "2025-01-14T11:49:03+00:00" }, { - "name": "nikic/php-parser", - "version": "v5.4.0", + "name": "nette/schema", + "version": "v1.2.5", "source": { "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + "url": "https://github.com/nette/schema.git", + "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "url": "https://api.github.com/repos/nette/schema/zipball/0462f0166e823aad657c9224d0f849ecac1ba10a", + "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a", + "shasum": "" + }, + "require": { + "nette/utils": "^2.5.7 || ^3.1.5 || ^4.0", + "php": "7.1 - 8.3" + }, + "require-dev": { + "nette/tester": "^2.3 || ^2.4", + "phpstan/phpstan-nette": "^1.0", + "tracy/tracy": "^2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "support": { + "issues": "https://github.com/nette/schema/issues", + "source": "https://github.com/nette/schema/tree/v1.2.5" + }, + "time": "2023-10-05T20:37:59+00:00" + }, + { + "name": "nette/utils", + "version": "v3.2.10", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "a4175c62652f2300c8017fb7e640f9ccb11648d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/a4175c62652f2300c8017fb7e640f9ccb11648d2", + "reference": "a4175c62652f2300c8017fb7e640f9ccb11648d2", + "shasum": "" + }, + "require": { + "php": ">=7.2 <8.4" + }, + "conflict": { + "nette/di": "<3.0.6" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "~2.0", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.3" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", + "ext-xml": "to use Strings::length() etc. when mbstring is not available" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v3.2.10" + }, + "time": "2023-07-30T15:38:18+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.6.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", "shasum": "" }, "require": { @@ -555,7 +967,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "5.x-dev" } }, "autoload": { @@ -579,9 +991,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" }, - "time": "2024-12-30T11:07:19+00:00" + "time": "2025-08-13T20:13:15+00:00" }, { "name": "nulib/base", @@ -589,18 +1001,23 @@ "dist": { "type": "path", "url": "../nulib-base", - "reference": "a319baec05c4022edc07f738a9f4cbad3e486b82" + "reference": "6a41b72e9517e39357cbb4a4983f57a839f3a495" }, "require": { "ext-json": "*", + "league/commonmark": "^2.4", "php": "^7.4", + "phpmailer/phpmailer": "^6.8", + "symfony/expression-language": "^5.4", "symfony/yaml": "^5.0" }, "replace": { - "nulib/php": "<0.6.0" + "nulib/php": "*" }, "require-dev": { "ext-curl": "*", + "ext-iconv": "*", + "ext-mbstring": "*", "ext-pcntl": "*", "ext-pdo": "*", "ext-pgsql": "*", @@ -608,6 +1025,15 @@ "ext-sqlite3": "*", "nulib/tests": "^7.4" }, + "bin": [ + "php/bin/dumpser.php", + "php/bin/csv2xlsx.php", + "php/bin/json2yml.php", + "php/bin/yml2json.php", + "php/bin/sqlite.capacitor.php", + "php/bin/mysql.capacitor.php", + "php/bin/pgsql.capacitor.php" + ], "type": "library", "extra": { "branch-alias": { @@ -617,7 +1043,8 @@ }, "autoload": { "psr-4": { - "nulib\\": "php/src" + "nulib\\": "php/src", + "cli\\": "php/cli" } }, "autoload-dev": { @@ -686,7 +1113,7 @@ "dist": { "type": "path", "url": "../nulib-spout", - "reference": "cc2bce3c206bd6b0a0405269db348d3936cf69f3" + "reference": "239c8aff8a5defa0e605f3d92df110b74c221f67" }, "require": { "ext-dom": "*", @@ -893,17 +1320,99 @@ "time": "2022-02-21T01:04:05+00:00" }, { - "name": "phpoffice/phpspreadsheet", - "version": "1.29.10", + "name": "phpmailer/phpmailer", + "version": "v6.11.1", "source": { "type": "git", - "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", - "reference": "c80041b1628c4f18030407134fe88303661d4e4e" + "url": "https://github.com/PHPMailer/PHPMailer.git", + "reference": "d9e3b36b47f04b497a0164c5a20f92acb4593284" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/c80041b1628c4f18030407134fe88303661d4e4e", - "reference": "c80041b1628c4f18030407134fe88303661d4e4e", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/d9e3b36b47f04b497a0164c5a20f92acb4593284", + "reference": "d9e3b36b47f04b497a0164c5a20f92acb4593284", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "php": ">=5.5.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "doctrine/annotations": "^1.2.6 || ^1.13.3", + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcompatibility/php-compatibility": "^9.3.5", + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "^3.7.2", + "yoast/phpunit-polyfills": "^1.0.4" + }, + "suggest": { + "decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication", + "ext-imap": "Needed to support advanced email address parsing according to RFC822", + "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", + "ext-openssl": "Needed for secure SMTP sending and DKIM signing", + "greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication", + "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", + "league/oauth2-google": "Needed for Google XOAUTH2 authentication", + "psr/log": "For optional PSR-3 debug logging", + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)", + "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPMailer\\PHPMailer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-only" + ], + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "support": { + "issues": "https://github.com/PHPMailer/PHPMailer/issues", + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.11.1" + }, + "funding": [ + { + "url": "https://github.com/Synchro", + "type": "github" + } + ], + "time": "2025-09-30T11:54:53+00:00" + }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.30.0", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "2f39286e0136673778b7a142b3f0d141e43d1714" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/2f39286e0136673778b7a142b3f0d141e43d1714", + "reference": "2f39286e0136673778b7a142b3f0d141e43d1714", "shasum": "" }, "require": { @@ -994,9 +1503,9 @@ ], "support": { "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", - "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.29.10" + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.30.0" }, - "time": "2025-02-08T02:56:14+00:00" + "time": "2025-08-10T06:28:02+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1319,16 +1828,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.23", + "version": "9.6.29", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95" + "reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", - "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9ecfec57835a5581bc888ea7e13b51eb55ab9dd3", + "reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3", "shasum": "" }, "require": { @@ -1339,7 +1848,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.1", + "myclabs/deep-copy": "^1.13.4", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=7.3", @@ -1350,11 +1859,11 @@ "phpunit/php-timer": "^5.0.3", "sebastian/cli-parser": "^1.0.2", "sebastian/code-unit": "^1.0.8", - "sebastian/comparator": "^4.0.8", + "sebastian/comparator": "^4.0.9", "sebastian/diff": "^4.0.6", "sebastian/environment": "^5.1.5", - "sebastian/exporter": "^4.0.6", - "sebastian/global-state": "^5.0.7", + "sebastian/exporter": "^4.0.8", + "sebastian/global-state": "^5.0.8", "sebastian/object-enumerator": "^4.0.4", "sebastian/resource-operations": "^3.0.4", "sebastian/type": "^3.2.1", @@ -1402,7 +1911,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.23" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.29" }, "funding": [ { @@ -1426,7 +1935,154 @@ "type": "tidelift" } ], - "time": "2025-05-02T06:40:34+00:00" + "time": "2025-09-24T06:29:11+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" }, { "name": "psr/http-client", @@ -1588,6 +2244,56 @@ }, "time": "2023-04-04T09:50:52+00:00" }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, { "name": "psr/simple-cache", "version": "1.0.1", @@ -1808,16 +2514,16 @@ }, { "name": "sebastian/comparator", - "version": "4.0.8", + "version": "4.0.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/67a2df3a62639eab2cc5906065e9805d4fd5dfc5", + "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5", "shasum": "" }, "require": { @@ -1870,15 +2576,27 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.9" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" } ], - "time": "2022-09-14T12:41:17+00:00" + "time": "2025-08-10T06:51:50+00:00" }, { "name": "sebastian/complexity", @@ -2068,16 +2786,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.6", + "version": "4.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" + "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", - "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/14c6ba52f95a36c3d27c835d65efc7123c446e8c", + "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c", "shasum": "" }, "require": { @@ -2133,28 +2851,40 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.8" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" } ], - "time": "2024-03-02T06:33:00+00:00" + "time": "2025-09-24T06:03:27+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.7", + "version": "5.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" + "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", - "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6", + "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6", "shasum": "" }, "require": { @@ -2197,15 +2927,27 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.8" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "type": "tidelift" } ], - "time": "2024-03-02T06:35:11+00:00" + "time": "2025-08-10T07:10:35+00:00" }, { "name": "sebastian/lines-of-code", @@ -2378,16 +3120,16 @@ }, { "name": "sebastian/recursion-context", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + "reference": "539c6691e0623af6dc6f9c20384c120f963465a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/539c6691e0623af6dc6f9c20384c120f963465a0", + "reference": "539c6691e0623af6dc6f9c20384c120f963465a0", "shasum": "" }, "require": { @@ -2429,15 +3171,27 @@ "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.6" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" } ], - "time": "2023-02-03T06:07:39+00:00" + "time": "2025-08-10T06:57:39+00:00" }, { "name": "sebastian/resource-operations", @@ -2602,6 +3356,182 @@ ], "time": "2020-09-28T06:39:44+00:00" }, + { + "name": "symfony/cache", + "version": "v5.4.46", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "0fe08ee32cec2748fbfea10c52d3ee02049e0f6b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/0fe08ee32cec2748fbfea10c52d3ee02049e0f6b", + "reference": "0fe08ee32cec2748fbfea10c52d3ee02049e0f6b", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/var-exporter": "^4.4|^5.0|^6.0" + }, + "conflict": { + "doctrine/dbal": "<2.13.1", + "symfony/dependency-injection": "<4.4", + "symfony/http-kernel": "<4.4", + "symfony/var-dumper": "<4.4" + }, + "provide": { + "psr/cache-implementation": "1.0|2.0", + "psr/simple-cache-implementation": "1.0|2.0", + "symfony/cache-implementation": "1.0|2.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "^1.6|^2.0", + "doctrine/dbal": "^2.13.1|^3|^4", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0", + "symfony/messenger": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v5.4.46" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-04T11:43:55+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v2.5.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "517c3a3619dadfa6952c4651767fcadffb4df65e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/517c3a3619dadfa6952c4651767fcadffb4df65e", + "reference": "517c3a3619dadfa6952c4651767fcadffb4df65e", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0|^3.0" + }, + "suggest": { + "symfony/cache-implementation": "" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "2.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:11:13+00:00" + }, { "name": "symfony/deprecation-contracts", "version": "v2.5.4", @@ -2669,9 +3599,72 @@ ], "time": "2024-09-25T14:11:13+00:00" }, + { + "name": "symfony/expression-language", + "version": "v5.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/expression-language.git", + "reference": "a784b66edc4c151eb05076d04707906ee2c209a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/a784b66edc4c151eb05076d04707906ee2c209a9", + "reference": "a784b66edc4c151eb05076d04707906ee2c209a9", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/cache": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ExpressionLanguage\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an engine that can compile and evaluate expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/expression-language/tree/v5.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-10-04T14:55:40+00:00" + }, { "name": "symfony/polyfill-ctype", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -2730,7 +3723,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -2741,6 +3734,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -2750,7 +3747,7 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", @@ -2811,7 +3808,258 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-23T08:48:59+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-02T08:10:11+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "f37b419f7aea2e9abf10abd261832cace12e3300" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f37b419f7aea2e9abf10abd261832cace12e3300", + "reference": "f37b419f7aea2e9abf10abd261832cace12e3300", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "2.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.4" }, "funding": [ { @@ -2827,7 +4075,80 @@ "type": "tidelift" } ], - "time": "2024-12-23T08:48:59+00:00" + "time": "2024-09-25T14:11:13+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v5.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "862700068db0ddfd8c5b850671e029a90246ec75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/862700068db0ddfd8c5b850671e029a90246ec75", + "reference": "862700068db0ddfd8c5b850671e029a90246ec75", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v5.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:11:13+00:00" }, { "name": "symfony/yaml", diff --git a/nur_bin/cachectl.php b/nur_bin/legacy-cachectl.php similarity index 100% rename from nur_bin/cachectl.php rename to nur_bin/legacy-cachectl.php diff --git a/src/app/app.php b/src/app/app.php deleted file mode 100644 index 52bfc79..0000000 --- a/src/app/app.php +++ /dev/null @@ -1,616 +0,0 @@ -getParams(); - } elseif ($app instanceof Application) { - $class = get_class($app); - $params = [ - "class" => $class, - "projdir" => $app::PROJDIR, - "vendor" => $app::VENDOR, - "appcode" => $app::APPCODE, - "datadir" => $app::DATADIR, - "etcdir" => $app::ETCDIR, - "vardir" => $app::VARDIR, - "logdir" => $app::LOGDIR, - "appgroup" => $app::APPGROUP, - "name" => $app::NAME, - "title" => $app::TITLE, - ]; - } elseif (self::isa_Application($app)) { - $class = $app; - $params = [ - "class" => $class, - "projdir" => constant("$app::PROJDIR"), - "vendor" => constant("$app::VENDOR"), - "appcode" => constant("$app::APPCODE"), - "datadir" => constant("$app::DATADIR"), - "etcdir" => constant("$app::ETCDIR"), - "vardir" => constant("$app::VARDIR"), - "logdir" => constant("$app::LOGDIR"), - "appgroup" => constant("$app::APPGROUP"), - "name" => constant("$app::NAME"), - "title" => constant("$app::TITLE"), - ]; - } elseif (is_array($app)) { - $params = $app; - } else { - throw ValueException::invalid_type($app, Application::class); - } - return $params; - } - - protected static ?self $app = null; - - /** - * @param Application|string|array $app - * @param Application|string|array|null $proj - */ - static function with($app, $proj=null): self { - $params = self::get_params($app); - $proj ??= self::params_getenv(); - $proj ??= self::$app; - $proj_params = $proj !== null? self::get_params($proj): null; - if ($proj_params !== null) { - A::merge($params, cl::select($proj_params, [ - "projdir", - "vendor", - "appcode", - "cwd", - "datadir", - "etcdir", - "vardir", - "logdir", - "profile", - "facts", - "debug", - ])); - } - return new static($params, $proj_params !== null); - } - - static function init($app, $proj=null): void { - self::$app = static::with($app, $proj); - } - - static function get(): self { - return self::$app ??= new static(null); - } - - static function params_putenv(): void { - $params = serialize(self::get()->getParams()); - putenv("NULIB_APP_app_params=$params"); - } - - static function params_getenv(): ?array { - $params = getenv("NULIB_APP_app_params"); - if ($params === false) return null; - return unserialize($params); - } - - static function get_profile(?bool &$productionMode=null): string { - return self::get()->getProfile($productionMode); - } - - static function is_prod(): bool { - return self::get_profile() === "prod"; - } - - static function is_devel(): bool { - return self::get_profile() === "devel"; - } - - static function set_profile(?string $profile=null, ?bool $productionMode=null): void { - self::get()->setProfile($profile, $productionMode); - } - - const FACT_WEB_APP = "web-app"; - const FACT_CLI_APP = "cli-app"; - - static final function is_fact(string $fact, $value=true): bool { - return self::get()->isFact($fact, $value); - } - - static final function set_fact(string $fact, $value=true): void { - self::get()->setFact($fact, $value); - } - - static function is_debug(): bool { - return self::get()->isDebug(); - } - - static function set_debug(?bool $debug=true): void { - self::get()->setDebug($debug); - } - - /** - * @var array rĂ©pertoires vendor exprimĂ©s relativement Ă  PROJDIR - */ - const DEFAULT_VENDOR = [ - "bindir" => "vendor/bin", - "autoload" => "vendor/autoload.php", - ]; - - function __construct(?array $params, bool $useProjParams=false) { - if ($useProjParams) { - [ - "projdir" => $projdir, - "vendor" => $vendor, - "appcode" => $appcode, - "datadir" => $datadir, - "etcdir" => $etcdir, - "vardir" => $vardir, - "logdir" => $logdir, - ] = $params; - $cwd = $params["cwd"] ?? null; - $datadirIsDefined = true; - } else { - # projdir - $projdir = $params["projdir"] ?? null; - if ($projdir === null) { - global $_composer_autoload_path, $_composer_bin_dir; - $autoload = $_composer_autoload_path ?? null; - $bindir = $_composer_bin_dir ?? null; - if ($autoload !== null) { - $vendor = preg_replace('/\/[^\/]+\.php$/', "", $autoload); - $bindir ??= "$vendor/bin"; - $projdir = preg_replace('/\/[^\/]+$/', "", $vendor); - $params["vendor"] = [ - "autoload" => $autoload, - "bindir" => $bindir, - ]; - } - } - if ($projdir === null) $projdir = "."; - $projdir = path::abspath($projdir); - # vendor - $vendor = $params["vendor"] ?? self::DEFAULT_VENDOR; - $vendor["bindir"] = path::reljoin($projdir, $vendor["bindir"]); - $vendor["autoload"] = path::reljoin($projdir, $vendor["autoload"]); - # appcode - $appcode = $params["appcode"] ?? null; - if ($appcode === null) { - $appcode = str::without_suffix("-app", path::basename($projdir)); - } - $APPCODE = str_replace("-", "_", strtoupper($appcode)); - # cwd - $cwd = $params["cwd"] ?? null; - # datadir - $datadir = getenv("${APPCODE}_DATADIR"); - $datadirIsDefined = $datadir !== false; - if ($datadir === false) $datadir = $params["datadir"] ?? null; - if ($datadir === null) $datadir = "devel"; - $datadir = path::reljoin($projdir, $datadir); - # etcdir - $etcdir = getenv("${APPCODE}_ETCDIR"); - if ($etcdir === false) $etcdir = $params["etcdir"] ?? null; - if ($etcdir === null) $etcdir = "etc"; - $etcdir = path::reljoin($datadir, $etcdir); - # vardir - $vardir = getenv("${APPCODE}_VARDIR"); - if ($vardir === false) $vardir = $params["vardir"] ?? null; - if ($vardir === null) $vardir = "var"; - $vardir = path::reljoin($datadir, $vardir); - # logdir - $logdir = getenv("${APPCODE}_LOGDIR"); - if ($logdir === false) $logdir = $params["logdir"] ?? null; - if ($logdir === null) $logdir = "log"; - $logdir = path::reljoin($datadir, $logdir); - } - # cwd - $cwd ??= getcwd(); - # profile - $this->profileManager = new ProfileManager([ - "app" => true, - "name" => $appcode, - "default_profile" => $datadirIsDefined? "prod": "devel", - "profile" => $params["profile"] ?? null, - ]); - # $facts - $this->facts = $params["facts"] ?? null; - # debug - $this->debug = $params["debug"] ?? null; - - $this->projdir = $projdir; - $this->vendor = $vendor; - $this->appcode = $appcode; - $this->cwd = $cwd; - $this->datadir = $datadir; - $this->etcdir = $etcdir; - $this->vardir = $vardir; - $this->logdir = $logdir; - - # name, title - $appgroup = $params["appgroup"] ?? null; - $name = $params["name"] ?? $params["class"] ?? null; - if ($name === null) { - $name = $appcode; - } else { - # si $name est une classe, enlever le package et normaliser i.e - # my\package\MyApplication --> my-application - $name = preg_replace('/.*\\\\/', "", $name); - $name = str::camel2us($name, false, "-"); - $name = str::without_suffix("-app", $name); - } - $this->appgroup = $appgroup; - $this->name = $name; - $this->title = $params["title"] ?? null; - } - - ############################################################################# - # ParamĂštres partagĂ©s par tous les scripts d'un projet (et les scripts lancĂ©s - # Ă  partir d'une application de ce projet) - - protected string $projdir; - - function getProjdir(): string { - return $this->projdir; - } - - protected array $vendor; - - function getVendorBindir(): string { - return $this->vendor["bindir"]; - } - - function getVendorAutoload(): string { - return $this->vendor["autoload"]; - } - - protected string $appcode; - - function getAppcode(): string { - return $this->appcode; - } - - protected string $cwd; - - function getCwd(): string { - return $this->cwd; - } - - protected string $datadir; - - function getDatadir(): string { - return $this->datadir; - } - - protected string $etcdir; - - function getEtcdir(): string { - return $this->etcdir; - } - - protected string $vardir; - - function getVardir(): string { - return $this->vardir; - } - - protected string $logdir; - - function getLogdir(): string { - return $this->logdir; - } - - protected ProfileManager $profileManager; - - function getProfile(?bool &$productionMode=null): string { - return $this->profileManager->getProfile($productionMode); - } - - function isProductionMode(): bool { - return $this->profileManager->isProductionMode(); - } - - function setProfile(?string $profile, ?bool $productionMode=null): void { - $this->profileManager->setProfile($profile, $productionMode); - } - - protected ?array $facts; - - function isFact(string $fact, $value=true): bool { - return ($this->facts[$fact] ?? false) === $value; - } - - function setFact(string $fact, $value=true): void { - $this->facts[$fact] = $value; - } - - protected ?bool $debug; - - function isDebug(): bool { - $debug = $this->debug; - if ($debug === null) { - $debug = defined("DEBUG")? DEBUG: null; - $DEBUG = getenv("DEBUG"); - $debug ??= $DEBUG !== false? $DEBUG: null; - $debug ??= config::k("debug"); - $debug ??= false; - $this->debug = $debug; - } - return $debug; - } - - function setDebug(bool $debug=true): void { - $this->debug = $debug; - } - - /** - * @param ?string|false $profile - * - * false === pas de profil - * null === profil par dĂ©faut - */ - function withProfile(string $file, $profile): string { - if ($profile !== false) { - $profile ??= $this->getProfile(); - [$dir, $filename] = path::split($file); - $basename = path::basename($filename); - $ext = path::ext($file); - $file = path::join($dir, "$basename.$profile$ext"); - } - return $file; - } - - function findFile(array $dirs, array $names, $profile=null): string { - # d'abord chercher avec le profil - if ($profile !== false) { - foreach ($dirs as $dir) { - foreach ($names as $name) { - $file = path::join($dir, $name); - $file = $this->withProfile($file, $profile); - if (file_exists($file)) return $file; - } - } - } - # puis sans profil - foreach ($dirs as $dir) { - foreach ($names as $name) { - $file = path::join($dir, $name); - if (file_exists($file)) return $file; - } - } - # la valeur par dĂ©faut est avec profil - return $this->withProfile(path::join($dirs[0], $names[0]), $profile); - } - - function fencedJoin(string $basedir, ?string ...$paths): string { - $path = path::reljoin($basedir, ...$paths); - if (!path::is_within($path, $basedir)) { - throw ValueException::invalid_value($path, "path"); - } - return $path; - } - - ############################################################################# - # ParamĂštres spĂ©cifiques Ă  cette application - - protected ?string $appgroup; - - function getAppgroup(): ?string { - return $this->appgroup; - } - - protected string $name; - - function getName(): ?string { - return $this->name; - } - - protected ?string $title; - - function getTitle(): ?string { - return $this->title; - } - - ############################################################################# - # MĂ©thodes outils - - /** recrĂ©er le tableau des paramĂštres */ - function getParams(): array { - return [ - "projdir" => $this->projdir, - "vendor" => $this->vendor, - "appcode" => $this->appcode, - "cwd" => $this->cwd, - "datadir" => $this->datadir, - "etcdir" => $this->etcdir, - "vardir" => $this->vardir, - "logdir" => $this->logdir, - "profile" => $this->getProfile(), - "facts" => $this->facts, - "debug" => $this->debug, - "appgroup" => $this->appgroup, - "name" => $this->name, - "title" => $this->title, - ]; - } - - /** - * obtenir le chemin vers le fichier de configuration. par dĂ©faut, retourner - * une valeur de la forme "$ETCDIR/$name[.$profile].conf" - */ - function getEtcfile(?string $name=null, $profile=null): string { - if ($name === null) $name = "{$this->name}.conf"; - return $this->findFile([$this->etcdir], [$name], $profile); - } - - /** - * obtenir le chemin vers le fichier de travail. par dĂ©faut, retourner une - * valeur de la forme "$VARDIR/$appgroup/$name[.$profile].tmp" - */ - function getVarfile(?string $name=null, $profile=null): string { - if ($name === null) $name = "{$this->name}.tmp"; - $file = $this->fencedJoin($this->vardir, $this->appgroup, $name); - $file = $this->withProfile($file, $profile); - sh::mkdirof($file); - return $file; - } - - /** - * obtenir le chemin vers le fichier de log. par dĂ©faut, retourner une - * valeur de la forme "$LOGDIR/$appgroup/$name.log" (sans le profil, parce - * qu'il s'agit du fichier de log par dĂ©faut) - * - * Si $name est spĂ©cifiĂ©, la valeur retournĂ©e sera de la forme - * "$LOGDIR/$appgroup/$basename[.$profile].$ext" - */ - function getLogfile(?string $name=null, $profile=null): string { - if ($name === null) { - $name = "{$this->name}.log"; - $profile ??= false; - } - $file = $this->fencedJoin($this->logdir, $this->appgroup, $name); - $file = $this->withProfile($file, $profile); - sh::mkdirof($file); - return $file; - } - - /** - * obtenir le chemin absolu vers un fichier de travail - * - si le chemin est absolu, il est inchangĂ© - * - sinon le chemin est exprimĂ© par rapport Ă  $vardir/$appgroup - * - * is $ensureDir, crĂ©er le rĂ©pertoire du fichier s'il n'existe pas dĂ©jĂ  - * - * la diffĂ©rence avec {@link self::getVarfile()} est que le fichier peut - * au final ĂȘtre situĂ© ailleurs que dans $vardir. de plus, il n'y a pas de - * valeur par dĂ©faut pour $file - */ - function getWorkfile(string $file, $profile=null, bool $ensureDir=true): string { - $file = path::reljoin($this->vardir, $this->appgroup, $file); - $file = $this->withProfile($file, $profile); - if ($ensureDir) sh::mkdirof($file); - return $file; - } - - /** - * obtenir le chemin absolu vers un fichier spĂ©cifiĂ© par l'utilisateur. - * - si le chemin commence par /, il est laissĂ© en l'Ă©tat - * - si le chemin commence par ./ ou ../, il est exprimĂ© par rapport Ă  $cwd - * - sinon le chemin est exprimĂ© par rapport Ă  $vardir/$appgroup - * - * la diffĂ©rence est avec {@link self::getVarfile()} est que le fichier peut - * au final ĂȘtre situĂ© ailleurs que dans $vardir. de plus, il n'y a pas de - * valeur par dĂ©faut pour $file - */ - function getUserfile(string $file): string { - if (path::is_qualified($file)) { - return path::reljoin($this->cwd, $file); - } else { - return path::reljoin($this->vardir, $this->appgroup, $file); - } - } - - protected ?RunFile $runfile = null; - - function getRunfile(): RunFile { - $name = $this->name; - $runfile = $this->getWorkfile($name); - $logfile = $this->getLogfile("$name.out", false); - return $this->runfile ??= new RunFile($name, $runfile, $logfile); - } - - protected ?array $lockFiles = null; - - function getLockfile(?string $name=null): LockFile { - $this->lockFiles[$name] ??= $this->getRunfile()->getLockFile($name, $this->title); - return $this->lockFiles[$name]; - } - - ############################################################################# - - const EC_FORK_CHILD = 250; - const EC_FORK_PARENT = 251; - const EC_DISABLED = 252; - const EC_LOCKED = 253; - const EC_BAD_COMMAND = 254; - const EC_UNEXPECTED = 255; - - ############################################################################# - - static bool $dispach_signals = false; - - static function install_signal_handler(bool $allow=true): void { - if (!$allow) return; - $signalHandler = function(int $signo, $siginfo) { - throw new ExitError(128 + $signo); - }; - pcntl_signal(SIGHUP, $signalHandler); - pcntl_signal(SIGINT, $signalHandler); - pcntl_signal(SIGQUIT, $signalHandler); - pcntl_signal(SIGTERM, $signalHandler); - self::$dispach_signals = true; - } - - static function _dispatch_signals() { - if (self::$dispach_signals) pcntl_signal_dispatch(); - } - - ############################################################################# - - static ?func $bgapplication_enabled = null; - - /** - * spĂ©cifier la fonction permettant de vĂ©rifier si l'exĂ©cution de tĂąches - * de fond est autorisĂ©e. Si cette mĂ©thode n'est pas utilisĂ©e, par dĂ©faut, - * les tĂąches planifiĂ©es sont autorisĂ©es - * - * si $func===true, spĂ©cifier une fonction qui retourne toujours vrai - * si $func===false, spĂ©cifiĂ©e une fonction qui retourne toujours faux - * sinon, $func doit ĂȘtre une fonction valide - */ - static function set_bgapplication_enabled($func): void { - if (is_bool($func)) { - $enabled = $func; - $func = function () use ($enabled) { - return $enabled; - }; - } - self::$bgapplication_enabled = func::with($func); - } - - /** - * Si les exĂ©cutions en tĂąche de fond sont autorisĂ©e, retourner. Sinon - * afficher une erreur et quitter l'application - */ - static function check_bgapplication_enabled(bool $forceEnabled=false): void { - if (self::$bgapplication_enabled === null || $forceEnabled) return; - if (!self::$bgapplication_enabled->invoke()) { - throw new ExitError(self::EC_DISABLED, "Planifications dĂ©sactivĂ©es. La tĂąche n'a pas Ă©tĂ© lancĂ©e"); - } - } - - ############################################################################# - - static function action(?string $title, ?int $maxSteps=null): void { - self::get()->getRunfile()->action($title, $maxSteps); - } - - static function step(int $nbSteps=1): void { - self::get()->getRunfile()->step($nbSteps); - } -} diff --git a/src/app/cli/AbstractArgsParser.php b/src/app/cli/AbstractArgsParser.php deleted file mode 100644 index 13aadba..0000000 --- a/src/app/cli/AbstractArgsParser.php +++ /dev/null @@ -1,108 +0,0 @@ - 0) throw $this->notEnoughArgs($count, $option); - } - - protected function tooManyArgs(int $count, int $expected, ?string $arg=null): ArgsException { - if ($arg !== null) $arg .= ": "; - return new ArgsException("${arg}trop d'arguments (attendu $expected, reçu $count)"); - } - - protected function invalidArg(string $arg): ArgsException { - return new ArgsException("$arg: argument invalide"); - } - - protected function ambiguousArg(string $arg, array $candidates): ArgsException { - $candidates = implode(", ", $candidates); - return new ArgsException("$arg: argument ambigĂ» (les valeurs possibles sont $candidates)"); - } - - /** - * consommer les arguments de $src en avançant l'index $srci et provisionner - * $dest Ă  partir de $desti. si $desti est plus grand que 0, celĂ  veut dire - * que $dest a dĂ©jĂ  commencĂ© Ă  ĂȘtre provisionnĂ©, et qu'il faut continuer. - * - * $destmin est le nombre minimum d'arguments Ă  consommer. $destmax est le - * nombre maximum d'arguments Ă  consommer. - * - * $srci est la position de l'Ă©lĂ©ment courant Ă  consommer le cas Ă©chĂ©ant - * retourner le nombre d'arguments qui manquent (ou 0 si tous les arguments - * ont Ă©tĂ© consommĂ©s) - * - * pour les arguments optionnels, ils sont consommĂ©s tant qu'il y en a de - * disponible, ou jusqu'Ă  la prĂ©sence de '--'. Si $keepsep, l'argument '--' - * est gardĂ© dans la liste des arguments optionnels. - */ - protected static function consume_args($src, &$srci, &$dest, $desti, $destmin, $destmax, bool $keepsep): int { - $srcmax = count($src); - # arguments obligatoires - while ($desti < $destmin) { - if ($srci < $srcmax) { - $dest[] = $src[$srci]; - } else { - # pas assez d'arguments - return $destmin - $desti; - } - $srci++; - $desti++; - } - # arguments facultatifs - $eoo = false; // l'option a-t-elle Ă©tĂ© terminĂ©e? - while ($desti < $destmax && $srci < $srcmax) { - $opt = $src[$srci]; - $srci++; - $desti++; - if ($opt === "--") { - # fin des arguments facultatifs en entrĂ©e - $eoo = true; - if ($keepsep) $dest[] = $opt; - break; - } - $dest[] = $opt; - } - if (!$eoo && $desti < $destmax) { - # pas assez d'arguments en entrĂ©e, terminer avec "--" - $dest[] = "--"; - } - return 0; - } - - abstract function normalize(array $args): array; - - /** @var object|array objet destination */ - protected $dest; - - protected function setDest(&$dest): void { - $this->dest =& $dest; - } - - protected function unsetDest(): void { - unset($this->dest); - } - - abstract function process(array $args); - - function parse(&$dest, array $args=null): void { - if ($args === null) { - global $argv; - $args = array_slice($argv, 1); - } - $args = $this->normalize($args); - $dest ??= new stdClass(); - $this->setDest($dest); - $this->process($args); - $this->unsetDest(); - } - - abstract function actionPrintHelp(string $arg): void; -} diff --git a/src/app/cli/Aodef.php b/src/app/cli/Aodef.php deleted file mode 100644 index 2ad7fa5..0000000 --- a/src/app/cli/Aodef.php +++ /dev/null @@ -1,620 +0,0 @@ -origDef = $def; - $this->mergeParse($def); - //$this->debugTrace("construct"); - } - - protected array $origDef; - - public bool $show = true; - public ?bool $disabled = null; - public ?bool $isRemains = null; - public ?string $extends = null; - - protected ?array $_removes = null; - protected ?array $_adds = null; - - protected ?array $_args = null; - public ?string $argsdesc = null; - - public ?bool $ensureArray = null; - public $action = null; - public ?func $func = null; - public ?bool $inverse = null; - public $value = null; - public ?string $name = null; - public ?string $property = null; - public ?string $key = null; - - public ?string $help = null; - - protected ?array $_options = []; - - public bool $haveShortOptions = false; - public bool $haveLongOptions = false; - public bool $isCommand = false; - public bool $isHelp = false; - - public bool $haveArgs = false; - public ?int $minArgs = null; - public ?int $maxArgs = null; - - protected function mergeParse(array $def): void { - $merges = $defs["merges"] ?? null; - $merge = $defs["merge"] ?? null; - if ($merge !== null) $merges[] = $merge; - if ($merges !== null) { - foreach ($merges as $merge) { - if ($merge !== null) $this->mergeParse($merge); - } - } - - $this->parse($def); - - $merge = $defs["merge_after"] ?? null; - if ($merge !== null) $this->mergeParse($merge); - } - - protected function parse(array $def): void { - [$options, $params] = cl::split_assoc($def); - - $this->show ??= $params["show"] ?? true; - $this->extends ??= $params["extends"] ?? null; - - $this->disabled = vbool::withn($params["disabled"] ?? null); - $removes = varray::withn($params["remove"] ?? null); - A::merge($this->_removes, $removes); - $adds = varray::withn($params["add"] ?? null); - A::merge($this->_adds, $adds); - A::merge($this->_adds, $options); - - $args = $params["args"] ?? null; - $args ??= $params["arg"] ?? null; - if ($args === true) $args = 1; - elseif ($args === "*") $args = [null]; - elseif ($args === "+") $args = ["value", null]; - if (is_int($args)) $args = array_fill(0, $args, "value"); - $this->_args ??= cl::withn($args); - - $this->argsdesc ??= $params["argsdesc"] ?? null; - - $this->ensureArray ??= $params["ensure_array"] ?? null; - $this->action = $params["action"] ?? null; - $this->inverse ??= $params["inverse"] ?? null; - $this->value ??= $params["value"] ?? null; - $this->name ??= $params["name"] ?? null; - $this->property ??= $params["property"] ?? null; - $this->key ??= $params["key"] ?? null; - - $this->help ??= $params["help"] ?? null; - } - - function isExtends(): bool { - return $this->extends !== null; - } - - function setup1(bool $extends=false, ?Aolist $aolist=null): void { - if (!$extends && !$this->isExtends()) { - $this->processOptions(); - } elseif ($extends && $this->isExtends()) { - $this->processExtends($aolist); - } - $this->initRemains(); - //$this->debugTrace("setup1"); - } - - protected function processExtends(Aolist $argdefs): void { - $option = $this->extends; - if ($option === null) { - throw ArgsException::missing("extends", "destination arg"); - } - $dest = $argdefs->get($option); - if ($dest === null) { - throw ArgsException::invalid($option, "destination arg"); - } - - if ($this->ensureArray !== null) $dest->ensureArray = $this->ensureArray; - if ($this->action !== null) $dest->action = $this->action; - if ($this->inverse !== null) $dest->inverse = $this->inverse; - if ($this->value !== null) $dest->value = $this->value; - if ($this->name !== null) $dest->name = $this->name; - if ($this->property !== null) $dest->property = $this->property; - if ($this->key !== null) $dest->key = $this->key; - - A::merge($dest->_removes, $this->_removes); - A::merge($dest->_adds, $this->_adds); - $dest->processOptions(); - } - - function buildOptions(?array $options): array { - $result = []; - if ($options !== null) { - foreach ($options as $option) { - if (substr($option, 0, 2) === "--") { - $type = self::TYPE_LONG; - if (preg_match('/^--([^:-][^:]*)(::?)?$/', $option, $ms)) { - $name = $ms[1]; - $args = $ms[2] ?? null; - $option = "--$name"; - } else { - throw ArgsException::invalid($option, "long option"); - } - } elseif (substr($option, 0, 1) === "-") { - $type = self::TYPE_SHORT; - if (preg_match('/^-([^:-])(::?)?$/', $option, $ms)) { - $name = $ms[1]; - $args = $ms[2] ?? null; - $option = "-$name"; - } else { - throw ArgsException::invalid($option, "short option"); - } - } else { - $type = self::TYPE_COMMAND; - if (preg_match('/^([^:-][^:]*)$/', $option, $ms)) { - $name = $ms[1]; - $args = null; - $option = "$name"; - } else { - throw ArgsException::invalid($option, "command"); - } - } - if ($args === ":") { - $argsType = self::ARGS_MANDATORY; - } elseif ($args === "::") { - $argsType = self::ARGS_OPTIONAL; - } else { - $argsType = self::ARGS_NONE; - } - $result[$option] = [ - "name" => $name, - "option" => $option, - "type" => $type, - "args_type" => $argsType, - ]; - } - } - return $result; - } - - protected function initRemains(): void { - if ($this->isRemains === null) { - $options = array_fill_keys(array_keys($this->_options), true); - foreach (array_keys($this->buildOptions($this->_removes)) as $option) { - unset($options[$option]); - } - foreach (array_keys($this->buildOptions($this->_adds)) as $option) { - unset($options[$option]); - } - if (!$options) $this->isRemains = true; - } - } - - /** traiter le paramĂštre parent */ - protected function processOptions(): void { - $this->removeOptions($this->_removes); - $this->_removes = null; - $this->addOptions($this->_adds); - $this->_adds = null; - } - - function addOptions(?array $options): void { - A::merge($this->_options, $this->buildOptions($options)); - $this->updateType(); - } - - function removeOptions(?array $options): void { - foreach ($this->buildOptions($options) as $option) { - unset($this->_options[$option["option"]]); - } - $this->updateType(); - } - - function removeOption(string $option): void { - unset($this->_options[$option]); - } - - /** mettre Ă  jour le type d'option */ - protected function updateType(): void { - $haveShortOptions = false; - $haveLongOptions = false; - $isCommand = false; - $isHelp = false; - foreach ($this->_options as $option) { - switch ($option["type"]) { - case self::TYPE_SHORT: - $haveShortOptions = true; - break; - case self::TYPE_LONG: - $haveLongOptions = true; - break; - case self::TYPE_COMMAND: - $isCommand = true; - break; - } - switch ($option["option"]) { - case "--help": - case "--help++": - $isHelp = true; - break; - } - } - $this->haveShortOptions = $haveShortOptions; - $this->haveLongOptions = $haveLongOptions; - $this->isCommand = $isCommand; - $this->isHelp = $isHelp; - } - - function setup2(): void { - $this->processArgs(); - $this->processAction(); - $this->afterSetup(); - //$this->debugTrace("setup2"); - } - - /** - * traiter les informations concernant les arguments puis calculer les nombres - * minimum et maximum d'arguments que prend l'option - */ - protected function processArgs(): void { - $args = $this->_args; - $haveArgs = boolval($args); - if ($this->isRemains) { - $haveArgs = true; - $args = [null]; - } elseif ($args === null) { - $optionalArgs = null; - foreach ($this->_options as $option) { - switch ($option["args_type"]) { - case self::ARGS_NONE: - break; - case self::ARGS_MANDATORY: - $haveArgs = true; - $optionalArgs = false; - break; - case self::ARGS_OPTIONAL: - $haveArgs = true; - $optionalArgs ??= true; - break; - } - } - $optionalArgs ??= false; - if ($haveArgs) { - $args = ["value"]; - if ($optionalArgs) $args = [$args]; - } - } - - if ($this->isRemains) $desc = "remaining args"; - else $desc = cl::first($this->_options)["option"]; - - $args ??= []; - $argsdesc = []; - $reqs = []; - $haveNull = false; - $optArgs = null; - foreach ($args as $arg) { - if (is_string($arg)) { - $reqs[] = $arg; - $argsdesc[] = strtoupper($arg); - } elseif (is_array($arg)) { - $optArgs = $arg; - break; - } elseif ($arg === null) { - $haveNull = true; - break; - } else { - throw ArgsException::invalid("$desc: $arg", "option arg"); - } - } - - $opts = []; - $optArgsdesc = null; - $lastarg = "VALUE"; - if ($optArgs !== null) { - $haveOpt = false; - foreach ($optArgs as $arg) { - if (is_string($arg)) { - $haveOpt = true; - $opts[] = $arg; - $lastarg = strtoupper($arg); - $optArgsdesc[] = $lastarg; - } elseif ($arg === null) { - $haveNull = true; - break; - } else { - throw ArgsException::invalid("$desc: $arg", "option arg"); - } - } - if (!$haveOpt) $haveNull = true; - } - if ($haveNull) $optArgsdesc[] = "${lastarg}s..."; - if ($optArgsdesc !== null) { - $argsdesc[] = "[".implode(" ", $optArgsdesc)."]"; - } - - $minArgs = count($reqs); - if ($haveNull) $maxArgs = PHP_INT_MAX; - else $maxArgs = $minArgs + count($opts); - - $this->haveArgs = $haveArgs; - $this->minArgs = $minArgs; - $this->maxArgs = $maxArgs; - $this->argsdesc ??= implode(" ", $argsdesc); - } - - private static function get_longest(array $options, int $type): ?string { - $longest = null; - $maxlen = 0; - foreach ($options as $option) { - if ($option["type"] !== $type) continue; - $name = $option["name"]; - $len = strlen($name); - if ($len > $maxlen) { - $longest = $name; - $maxlen = $len; - } - } - return $longest; - } - - protected function processAction(): void { - $this->ensureArray ??= $this->isRemains || $this->maxArgs > 1; - - $action = $this->action; - $func = $this->func; - if ($action === null) { - if ($this->isCommand) $action = "--set-command"; - elseif ($this->isRemains) $action = "--set-args"; - elseif ($this->isHelp) $action = "--show-help"; - elseif ($this->haveArgs) $action = "--set"; - elseif ($this->value !== null) $action = "--set"; - else $action = "--inc"; - } - if (is_string($action) && substr($action, 0, 2) === "--") { - # fonction interne - } else { - $func = func::with($action); - $action = "--func"; - } - $this->action = $action; - $this->func = $func; - - $name = $this->name; - $property = $this->property; - $key = $this->key; - if ($action !== "--func" && !$this->isRemains && - $name === null && $property === null && $key === null - ) { - # si on ne prĂ©cise pas le nom de la propriĂ©tĂ©, la dĂ©river Ă  partir du - # nom de l'option la plus longue - $longest = self::get_longest($this->_options, self::TYPE_LONG); - $longest ??= self::get_longest($this->_options, self::TYPE_COMMAND); - $longest ??= self::get_longest($this->_options, self::TYPE_SHORT); - if ($longest !== null) { - $longest = preg_replace('/[^A-Za-z0-9]+/', "_", $longest); - if (preg_match('/^[0-9]/', $longest)) { - # le nom de la propriĂ©tĂ© ne doit pas commencer par un chiffre - $longest = "p$longest"; - } - $name = $longest; - } - } elseif ($name === null && $property !== null) { - $name = $property; - } elseif ($name === null && $key !== null) { - $name = $key; - } - $this->name = $name; - } - - protected function afterSetup(): void { - $this->disabled ??= false; - $this->ensureArray ??= false; - $this->inverse ??= false; - if (str::del_prefix($this->help, "++")) { - $this->show = false; - } - } - - function getOptions(): array { - if ($this->disabled) return []; - else return array_keys($this->_options); - } - - function isEmpty(): bool { - return $this->disabled || !$this->_options; - } - - function printHelp(?array $what=null): void { - $showDef = $what["show"] ?? $this->show; - if (!$showDef) return; - - $prefix = $what["prefix"] ?? null; - if ($prefix !== null) echo $prefix; - - $showOptions = $what["options"] ?? true; - if ($showOptions) { - echo " "; - echo implode(", ", array_keys($this->_options)); - if ($this->haveArgs) { - echo " "; - echo $this->argsdesc; - } - echo "\n"; - } - - $showHelp = $what["help"] ?? true; - if ($this->help && $showHelp) { - echo str::indent($this->help, " "); - echo "\n"; - } - } - - function action(&$dest, $value, ?string $arg, AbstractArgsParser $parser): void { - if ($this->ensureArray) { - varray::ensure($value); - } elseif (is_array($value)) { - $count = count($value); - if ($count == 0) $value = null; - elseif ($count == 1) $value = $value[0]; - } - - switch ($this->action) { - case "--set": $this->actionSet($dest, $value); break; - case "--inc": $this->actionInc($dest); break; - case "--dec": $this->actionDec($dest); break; - case "--add": $this->actionAdd($dest, $value); break; - case "--adds": $this->actionAdds($dest, $value); break; - case "--merge": $this->actionMerge($dest, $value); break; - case "--merges": $this->actionMerges($dest, $value); break; - case "--func": $this->func->bind($dest)->invoke([$value, $arg, $this]); break; - case "--set-args": $this->actionSetArgs($dest, $value); break; - case "--set-command": $this->actionSetCommand($dest, $value); break; - case "--show-help": $parser->actionPrintHelp($arg); break; - default: throw ArgsException::invalid($this->action, "arg action"); - } - } - - function actionSet(&$dest, $value): void { - if ($this->property !== null) { - oprop::set($dest, $this->property, $value); - } elseif ($this->key !== null) { - akey::set($dest, $this->key, $value); - } elseif ($this->name !== null) { - valx::set($dest, $this->name, $value); - } - } - - function actionInc(&$dest): void { - if ($this->property !== null) { - if ($this->inverse) oprop::dec($dest, $this->property); - else oprop::inc($dest, $this->property); - } elseif ($this->key !== null) { - if ($this->inverse) akey::dec($dest, $this->key); - else akey::inc($dest, $this->key); - } elseif ($this->name !== null) { - if ($this->inverse) valx::dec($dest, $this->name); - else valx::inc($dest, $this->name); - } - } - - function actionDec(&$dest): void { - if ($this->property !== null) { - if ($this->inverse) oprop::inc($dest, $this->property); - else oprop::dec($dest, $this->property); - } elseif ($this->key !== null) { - if ($this->inverse) akey::inc($dest, $this->key); - else akey::dec($dest, $this->key); - } elseif ($this->name !== null) { - if ($this->inverse) valx::inc($dest, $this->name); - else valx::dec($dest, $this->name); - } - } - - function actionAdd(&$dest, $value): void { - if ($this->property !== null) { - oprop::append($dest, $this->property, $value); - } elseif ($this->key !== null) { - akey::append($dest, $this->key, $value); - } elseif ($this->name !== null) { - valx::append($dest, $this->name, $value); - } - } - - function actionAdds(&$dest, $value): void { - if ($this->property !== null) { - foreach (cl::with($value) as $value) { - oprop::append($dest, $this->property, $value); - } - } elseif ($this->key !== null) { - foreach (cl::with($value) as $value) { - akey::append($dest, $this->key, $value); - } - } elseif ($this->name !== null) { - foreach (cl::with($value) as $value) { - valx::append($dest, $this->name, $value); - } - } - } - - function actionMerge(&$dest, $value): void { - if ($this->property !== null) { - oprop::merge($dest, $this->property, $value); - } elseif ($this->key !== null) { - akey::merge($dest, $this->key, $value); - } elseif ($this->name !== null) { - valx::merge($dest, $this->name, $value); - } - } - - function actionMerges(&$dest, $value): void { - if ($this->property !== null) { - foreach (cl::with($value) as $value) { - oprop::merge($dest, $this->property, $value); - } - } elseif ($this->key !== null) { - foreach (cl::with($value) as $value) { - akey::merge($dest, $this->key, $value); - } - } elseif ($this->name !== null) { - foreach (cl::with($value) as $value) { - valx::merge($dest, $this->name, $value); - } - } - } - - function actionSetArgs(&$dest, $value): void { - if ($this->property !== null) { - oprop::set($dest, $this->property, $value); - } elseif ($this->key !== null) { - akey::set($dest, $this->key, $value); - } elseif ($this->name !== null) { - valx::set($dest, $this->name, $value); - } - } - - function actionSetCommand(&$dest, $value): void { - if ($this->property !== null) { - oprop::set($dest, $this->property, $value); - } elseif ($this->key !== null) { - akey::set($dest, $this->key, $value); - } elseif ($this->name !== null) { - valx::set($dest, $this->name, $value); - } - } - - function __toString(): string { - $options = implode(",", $this->getOptions()); - $args = $this->haveArgs? " ({$this->minArgs}-{$this->maxArgs})": false; - return "$options$args"; - } - private function debugTrace(string $message): void { - $options = implode(",", cl::split_assoc($this->origDef)[0] ?? []); - echo "$options $message\n"; - } -} diff --git a/src/app/cli/Aogroup.php b/src/app/cli/Aogroup.php deleted file mode 100644 index 6553c5a..0000000 --- a/src/app/cli/Aogroup.php +++ /dev/null @@ -1,36 +0,0 @@ -all() as $aodef) { - $firstAodef ??= $aodef; - $aodef->printHelp(["help" => false]); - } - if ($firstAodef !== null) { - $firstAodef->printHelp(["options" => false]); - } - } -} diff --git a/src/app/cli/Aolist.php b/src/app/cli/Aolist.php deleted file mode 100644 index 820c69f..0000000 --- a/src/app/cli/Aolist.php +++ /dev/null @@ -1,268 +0,0 @@ -origDefs = $defs; - $this->initDefs($defs, $setup); - } - - protected array $origDefs; - - protected ?array $aomain; - protected ?array $aosections; - protected ?array $aospecials; - - public ?Aodef $remainsArgdef = null; - - function initDefs(array $defs, bool $setup=true): void { - $this->mergeParse($defs, $aobjects); - $this->aomain = $aobjects["main"] ?? null; - $this->aosections = $aobjects["sections"] ?? null; - $this->aospecials = $aobjects["specials"] ?? null; - if ($setup) $this->setup(); - } - - protected function mergeParse(array $defs, ?array &$aobjects, bool $parse=true): void { - $aobjects ??= []; - - $merges = $defs["merges"] ?? null; - $merge = $defs["merge"] ?? null; - if ($merge !== null) $merges[] = $merge; - if ($merges !== null) { - foreach ($merges as $merge) { - $this->mergeParse($merge, $aobjects, false); - $this->parse($merge, $aobjects); - } - } - - if ($parse) $this->parse($defs, $aobjects); - - $merge = $defs["merge_after"] ?? null; - if ($merge !== null) { - $this->mergeParse($merge, $aobjects, false); - $this->parse($merge, $aobjects); - } - } - - protected function parse(array $defs, array &$aobjects): void { - [$defs, $params] = cl::split_assoc($defs); - if ($defs !== null) { - $aomain =& $aobjects["main"]; - foreach ($defs as $def) { - $first = $def[0] ?? null; - if ($first === "group") { - $aobject = new Aogroup($def); - } else { - $aobject = new Aodef($def); - } - $aomain[] = $aobject; - } - } - $sections = $params["sections"] ?? null; - if ($sections !== null) { - $aosections =& $aobjects["sections"]; - $index = 0; - foreach ($sections as $key => $section) { - if ($key === $index) { - $index++; - $aosections[] = new Aosection($section); - } else { - /** @var Aosection $aosection */ - $aosection = $aosections[$key] ?? null; - if ($aosection === null) { - $aosections[$key] = new Aosection($section); - } else { - #XXX il faut implĂ©menter la fusion en cas de section existante - # pour le moment, la liste existante est Ă©crasĂ©e - $aosection->initDefs($section); - } - } - } - } - $this->parseParams($params); - } - - protected function parseParams(?array $params): void { - } - - function all(?array $what=null): iterable { - $returnsAodef = $what["aodef"] ?? true; - $returnsAolist = $what["aolist"] ?? false; - $returnExtends = $what["extends"] ?? false; - $withSpecials = $what["aospecials"] ?? true; - # lister les sections avant, pour que les options de la section principale - # soient prioritaires - $aosections = $this->aosections; - if ($aosections !== null) { - /** @var Aosection $aobject */ - foreach ($aosections as $aosection) { - if ($returnsAolist) { - yield $aosection; - } elseif ($returnsAodef) { - yield from $aosection->all($what); - } - } - } - - $aomain = $this->aomain; - if ($aomain !== null) { - /** @var Aodef $aobject */ - foreach ($aomain as $aobject) { - if ($aobject instanceof Aodef) { - if ($returnsAodef) { - if ($returnExtends) { - if ($aobject->isExtends()) yield $aobject; - } else { - if (!$aobject->isExtends()) yield $aobject; - } - } - } elseif ($aobject instanceof Aolist) { - if ($returnsAolist) { - yield $aobject; - } elseif ($returnsAodef) { - yield from $aobject->all($what); - } - } - } - } - - $aospecials = $this->aospecials; - if ($withSpecials && $aospecials !== null) { - /** @var Aodef $aobject */ - foreach ($aospecials as $aobject) { - yield $aobject; - } - } - } - - protected function filter(callable $callback): void { - $aomain = $this->aomain; - if ($aomain !== null) { - $filtered = []; - /** @var Aodef $aobject */ - foreach ($aomain as $aobject) { - if ($aobject instanceof Aolist) { - $aobject->filter($callback); - } - if (call_user_func($callback, $aobject)) { - $filtered[] = $aobject; - } - } - $this->aomain = $filtered; - } - $aosections = $this->aosections; - if ($aosections !== null) { - $filtered = []; - /** @var Aosection $aosection */ - foreach ($aosections as $aosection) { - $aosection->filter($callback); - if (call_user_func($callback, $aosection)) { - $filtered[] = $aosection; - } - } - $this->aosections = $filtered; - } - } - - protected function setup(): void { - # calculer les options - foreach ($this->all() as $aodef) { - $aodef->setup1(); - } - /** @var Aodef $aodef */ - foreach ($this->all(["extends" => true]) as $aodef) { - $aodef->setup1(true, $this); - } - # ne garder que les objets non vides - $this->filter(function($aobject): bool { - if ($aobject instanceof Aodef) { - return !$aobject->isEmpty(); - } elseif ($aobject instanceof Aolist) { - return !$aobject->isEmpty(); - } else { - return false; - } - }); - # puis calculer nombre d'arguments et actions - foreach ($this->all() as $aodef) { - $aodef->setup2(); - } - } - - function isEmpty(): bool { - foreach ($this->all() as $aobject) { - return false; - } - return true; - } - - function get(string $option): ?Aodef { - return null; - } - - function actionPrintHelp(string $arg): void { - $this->printHelp([ - "show_all" => $arg === "--help++", - ]); - } - - function printHelp(?array $what=null): void { - $show = $what["show_all"] ?? false; - if (!$show) $show = null; - - $aosections = $this->aosections; - if ($aosections !== null) { - /** @var Aosection $aosection */ - foreach ($aosections as $aosection) { - $aosection->printHelp(cl::merge($what, [ - "show" => $show, - "prefix" => "\n", - ])); - } - } - - $aomain = $this->aomain; - if ($aomain !== null) { - echo "\nOPTIONS\n"; - foreach ($aomain as $aobject) { - $aobject->printHelp(cl::merge($what, [ - "show" => $show, - ])); - } - } - } - - function __toString(): string { - $items = []; - $what = [ - "aodef" => true, - "aolist" => true, - ]; - foreach ($this->all($what) as $aobject) { - if ($aobject instanceof Aodef) { - $items[] = strval($aobject); - } elseif ($aobject instanceof Aogroup) { - $items[] = implode("\n", [ - "group", - str::indent(strval($aobject)), - ]); - } elseif ($aobject instanceof Aosection) { - $items[] = implode("\n", [ - "section", - str::indent(strval($aobject)), - ]); - } else { - $items[] = false; - } - } - return implode("\n", $items); - } -} diff --git a/src/app/cli/Aosection.php b/src/app/cli/Aosection.php deleted file mode 100644 index 54485d8..0000000 --- a/src/app/cli/Aosection.php +++ /dev/null @@ -1,45 +0,0 @@ -show = vbool::with($params["show"] ?? true); - $this->prefix ??= $params["prefix"] ?? null; - $this->title ??= $params["title"] ?? null; - $this->description ??= $params["description"] ?? null; - $this->suffix ??= $params["suffix"] ?? null; - } - - function printHelp(?array $what=null): void { - $showSection = $what["show"] ?? $this->show; - if (!$showSection) return; - - $prefix = $what["prefix"] ?? null; - if ($prefix !== null) echo $prefix; - - if ($this->prefix) echo "{$this->prefix}\n"; - if ($this->title) echo "{$this->title}\n"; - if ($this->description) echo "\n{$this->description}\n"; - /** @var Aodef|Aolist $aobject */ - foreach ($this->all(["aolist" => true]) as $aobject) { - $aobject->printHelp(); - } - if ($this->suffix) echo "{$this->suffix}\n"; - } -} diff --git a/src/app/cli/Application.php b/src/app/cli/Application.php deleted file mode 100644 index d130eee..0000000 --- a/src/app/cli/Application.php +++ /dev/null @@ -1,378 +0,0 @@ -getDesc(); - echo implode("\n", $desc["message"])."\n"; - $ec = $desc["exitcode"] ?? 0; - break; - case "dump": - case "d": - yaml::dump($runfile->read()); - break; - case "reset": - case "z": - if (!$runfile->isRunning()) $runfile->reset(); - else $ec = self::_error("cannot reset while running"); - break; - case "release": - case "rl": - $runfile->release(); - break; - case "start": - case "s": - array_splice($argv, 1, 1); $argc--; - return; - case "kill": - case "k": - if ($runfile->isRunning()) $runfile->wfKill(); - else $ec = self::_error("not running"); - break; - default: - $ec = self::_error("$argv[1]: unexpected command", app::EC_BAD_COMMAND); - } - exit($ec); - } - - static function run(?Application $app=null): void { - $unlock = false; - $stop = false; - $shutdown = function () use (&$unlock, &$stop) { - if ($unlock) { - app::get()->getRunfile()->release(); - $unlock = false; - } - if ($stop) { - app::get()->getRunfile()->wfStop(); - $stop = false; - } - }; - register_shutdown_function($shutdown); - app::install_signal_handler(static::INSTALL_SIGNAL_HANDLER); - try { - static::_initialize_app(); - $useRunfile = static::USE_RUNFILE; - $useRunlock = static::USE_RUNLOCK; - if ($useRunfile) { - $runfile = app::get()->getRunfile(); - - global $argc, $argv; - self::_manage_runfile($argc, $argv, $runfile); - if ($useRunlock && $runfile->warnIfLocked()) exit(app::EC_LOCKED); - - $runfile->wfStart(); - $stop = true; - if ($useRunlock) { - $runfile->lock(); - $unlock = true; - } - } - if ($app === null) $app = new static(); - static::_configure_app($app); - static::_start_app($app); - } catch (ExitError $e) { - if ($e->haveUserMessage()) msg::error($e->getUserMessage()); - exit($e->getCode()); - } catch (Exception $e) { - msg::error($e); - exit(app::EC_UNEXPECTED); - } - } - - protected static function _initialize_app(): void { - app::init(static::class); - app::set_fact(app::FACT_CLI_APP); - msg::set_messenger(new StdMessenger([ - "min_level" => msg::DEBUG, - ])); - } - - protected static function _configure_app(Application $app): void { - config::configure(config::CONFIGURE_INITIAL_ONLY); - - $msgs = null; - $msgs["console"] = new StdMessenger([ - "min_level" => msg::NORMAL, - ]); - if (static::USE_LOGFILE) { - $msgs["log"] = new StdMessenger([ - "output" => app::get()->getLogfile(), - "min_level" => msg::MINOR, - "add_date" => true, - ]); - } - msg::init($msgs); - - $app->parseArgs(); - config::configure(); - } - - protected static function _start_app(Application $app): void { - $retcode = $app->main(); - if (is_int($retcode)) exit($retcode); - elseif (is_bool($retcode)) exit($retcode? 0: 1); - elseif ($retcode !== null) exit(strval($retcode)); - } - - /** - * sortir de l'application avec un code d'erreur, qui est 0 par dĂ©faut (i.e - * pas d'erreur) - * - * Ă©quivalent Ă  lancer l'exception {@link ExitError} - */ - protected static final function exit(int $exitcode=0, $message=null) { - throw new ExitError($exitcode, $message); - } - - /** - * sortir de l'application avec un code d'erreur, qui vaut 1 par dĂ©faut (i.e - * une erreur s'est produite) - * - * Ă©quivalent Ă  lancer l'exception {@link ExitError} - */ - protected static final function die($message=null, int $exitcode=1) { - throw new ExitError($exitcode, $message); - } - - const PROFILE_SECTION = [ - "title" => "PROFILS D'EXECUTION", - "show" => false, - ["group", - ["-p", "--profile", "--app-profile", - "args" => "profile", - "action" => [app::class, "set_profile"], - "help" => "spĂ©cifier le profil d'exĂ©cution", - ], - ["-P", "--prod", "action" => [app::class, "set_profile", config::PROD]], - ["-T", "--test", "action" => [app::class, "set_profile", config::TEST]], - ["--devel", "action" => [app::class, "set_profile", config::DEVEL]], - ], - ]; - - const VERBOSITY_SECTION = [ - "title" => "NIVEAU D'INFORMATION", - "show" => false, - ["group", - ["--verbosity", - "args" => "verbosity", "argsdesc" => "silent|quiet|verbose|debug", - "action" => [null, "set_application_verbosity"], - "help" => "spĂ©cifier le niveau d'informations affichĂ©", - ], - ["-q", "--quiet", "action" => [null, "set_application_verbosity", "quiet"]], - ["-v", "--verbose", "action" => [null, "set_application_verbosity", "verbose"]], - ["-D", "--debug", "action" => [null, "set_application_verbosity", "debug"]], - ], - ["-L", "--logfile", - "args" => "output", - "action" => [null, "set_application_log_output"], - "help" => "Logger les messages de l'application dans le fichier spĂ©cifiĂ©", - ], - ["group", - ["--color", - "action" => [null, "set_application_color", true], - "help" => "Afficher (resp. ne pas afficher) la sortie en couleur par dĂ©faut", - ], - ["--no-color", "action" => [null, "set_application_color", false]], - ], - ]; - - static function set_application_verbosity(string $verbosity): void { - $console = console::get(); - switch ($verbosity) { - case "Q": - case "silent": - $console->resetParams([ - "min_level" => msg::NONE, - ]); - break; - case "q": - case "quiet": - $console->resetParams([ - "min_level" => msg::MAJOR, - ]); - break; - case "n": - case "normal": - $console->resetParams([ - "min_level" => msg::NORMAL, - ]); - break; - case "v": - case "verbose": - $console->resetParams([ - "min_level" => msg::MINOR, - ]); - break; - case "D": - case "debug": - config::set_debug(); - $console->resetParams([ - "min_level" => msg::DEBUG, - ]); - break; - default: - throw ValueException::invalid_value($verbosity, "verbosity"); - } - } - - static function set_application_log_output(string $logfile): void { - log::create_or_reset_params([ - "output" => $logfile, - ], StdMessenger::class, [ - "add_date" => true, - "min_level" => log::MINOR, - ]); - } - static function set_application_color(bool $color): void { - console::reset_params([ - "color" => $color, - ]); - } - const ARGS = [ - "sections" => [ - self::PROFILE_SECTION, - self::VERBOSITY_SECTION, - ], - ]; - - protected function getArgsParser(): AbstractArgsParser { - return new SimpleArgsParser(static::ARGS); - } - - /** @throws ArgsException */ - function parseArgs(array $args=null): void { - $this->getArgsParser()->parse($this, $args); - } - - const PROFILE_COLORS = [ - "prod" => "@r", - "test" => "@g", - "devel" => "@w", - ]; - const DEFAULT_PROFILE_COLOR = "y"; - - /** retourner le profil courant en couleur */ - static function get_profile(?string $profile=null): string { - if ($profile === null) $profile = app::get_profile(); - foreach (static::PROFILE_COLORS as $text => $color) { - if (strpos($profile, $text) !== false) { - return $color? "$profile": $profile; - } - } - $color = static::DEFAULT_PROFILE_COLOR; - return $color? "$profile": $profile; - } - - abstract function main(); - - static function runfile(): RunFile { - return app::with(static::class)->getRunfile(); - } -} diff --git a/src/app/cli/ArgsException.php b/src/app/cli/ArgsException.php deleted file mode 100644 index bfb818a..0000000 --- a/src/app/cli/ArgsException.php +++ /dev/null @@ -1,20 +0,0 @@ -prefix ??= $params["prefix"] ?? null; - $this->name ??= $params["name"] ?? null; - $this->purpose ??= $params["purpose"] ?? null; - $this->usage ??= $params["usage"] ?? null; - $this->description ??= $params["description"] ?? null; - $this->suffix ??= $params["suffix"] ?? null; - - $this->commandname ??= $params["commandname"] ?? null; - $this->commandproperty ??= $params["commandproperty"] ?? null; - $this->commandkey ??= $params["commandkey"] ?? null; - - $this->argsname ??= $params["argsname"] ?? null; - $this->argsproperty ??= $params["argsproperty"] ?? null; - $this->argskey ??= $params["argskey"] ?? null; - - $this->autohelp ??= vbool::withn($params["autohelp"] ?? null); - $this->autoremains ??= vbool::withn($params["autoremains"] ?? null); - } - - /** @return string[] */ - function getOptions(): array { - return array_keys($this->index); - } - - protected function indexAodefs(): void { - $this->index = []; - foreach ($this->all() as $aodef) { - $options = $aodef->getOptions(); - foreach ($options as $option) { - /** @var Aodef $prevAodef */ - $prevAodef = $this->index[$option] ?? null; - if ($prevAodef !== null) $prevAodef->removeOption($option); - $this->index[$option] = $aodef; - } - } - } - - protected function setup(): void { - # calculer les options pour les objets dĂ©jĂ  fusionnĂ©s - /** @var Aodef $aodef */ - foreach ($this->all() as $aodef) { - $aodef->setup1(); - } - - # puis traiter les extensions d'objets et calculer les options pour ces - # objets sur la base de l'index que l'on crĂ©e une premiĂšre fois - $this->indexAodefs(); - /** @var Aodef $aodef */ - foreach ($this->all(["extends" => true]) as $aodef) { - $aodef->setup1(true, $this); - } - - # ne garder que les objets non vides - $this->filter(function($aobject) { - if ($aobject instanceof Aodef) { - return !$aobject->isEmpty(); - } elseif ($aobject instanceof Aolist) { - return !$aobject->isEmpty(); - } else { - return false; - } - }); - - # rajouter remains et help si nĂ©cessaire - $this->aospecials = []; - $helpArgdef = null; - $remainsArgdef = null; - /** @var Aodef $aodef */ - foreach ($this->all() as $aodef) { - if ($aodef->isHelp) $helpArgdef = $aodef; - if ($aodef->isRemains) $remainsArgdef = $aodef; - } - - $this->autohelp ??= true; - if ($helpArgdef === null && $this->autohelp) { - $helpArgdef = new Aodef([ - "--help", "--help++", - "action" => "--show-help", - "help" => "Afficher l'aide", - ]); - $helpArgdef->setup1(); - } - if ($helpArgdef !== null) $this->aospecials[] = $helpArgdef; - - $this->autoremains ??= true; - if ($remainsArgdef === null && $this->autoremains) { - $remainsArgdef = new Aodef([ - "args" => [null], - "action" => "--set-args", - "name" => $this->argsname ?? "args", - "property" => $this->argsproperty, - "key" => $this->argskey, - ]); - $remainsArgdef->setup1(); - } - if ($remainsArgdef !== null) { - $this->remainsArgdef = $remainsArgdef; - $this->aospecials[] = $remainsArgdef; - } - - # puis calculer nombre d'arguments et actions - $this->indexAodefs(); - /** @var Aodef $aodef */ - foreach ($this->all() as $aodef) { - $aodef->setup2(); - } - } - - function get(string $option): ?Aodef { - return $this->index[$option] ?? null; - } - - function printHelp(?array $what = null): void { - $showList = $what["show"] ?? true; - if (!$showList) return; - - $prefix = $what["prefix"] ?? null; - if ($prefix !== null) echo $prefix; - - if ($this->prefix) echo "{$this->prefix}\n"; - if ($this->purpose) { - echo "{$this->name}: {$this->purpose}\n"; - } elseif (!$this->prefix) { - # s'il y a un prĂ©fixe sans purpose, il remplace purpose - echo "{$this->name}\n"; - } - if ($this->usage) { - echo "\nUSAGE\n"; - foreach (cl::with($this->usage) as $usage) { - echo " {$this->name} $usage\n"; - } - } - if ($this->description) echo "\n{$this->description}\n"; - parent::printHelp($what); - if ($this->suffix) echo "{$this->suffix}\n"; - } - - function __toString(): string { - return implode("\n", [ - "objects:", - str::indent(parent::__toString()), - "index:", - str::indent(implode("\n", array_keys($this->index))), - ]); - } -} diff --git a/src/app/cli/SimpleArgsParser.php b/src/app/cli/SimpleArgsParser.php deleted file mode 100644 index 2141a16..0000000 --- a/src/app/cli/SimpleArgsParser.php +++ /dev/null @@ -1,247 +0,0 @@ -aolist = new SimpleAolist($defs); - } - - protected SimpleAolist $aolist; - - protected function getArgdef(string $option): ?Aodef { - return $this->aolist->get($option); - } - - protected function getOptions(): array { - return $this->aolist->getOptions(); - } - - function normalize(array $args): array { - $i = 0; - $max = count($args); - $options = []; - $remains = []; - $parseOpts = true; - while ($i < $max) { - $arg = $args[$i++]; - if (!$parseOpts) { - # le reste n'est que des arguments - $remains[] = $arg; - continue; - } - if ($arg === "--") { - # fin des options - $parseOpts = false; - continue; - } - - if (substr($arg, 0, 2) === "--") { - ####################################################################### - # option longue - $pos = strpos($arg, "="); - if ($pos !== false) { - # option avec valeur - $option = substr($arg, 0, $pos); - $value = substr($arg, $pos + 1); - } else { - # option sans valeur - $option = $arg; - $value = null; - } - $argdef = $this->getArgdef($option); - if ($argdef === null) { - # chercher une correspondance - $len = strlen($option); - $candidates = []; - foreach ($this->getOptions() as $candidate) { - if (substr($candidate, 0, $len) === $option) { - $candidates[] = $candidate; - } - } - switch (count($candidates)) { - case 0: throw $this->invalidArg($option); - case 1: $option = $candidates[0]; break; - default: throw $this->ambiguousArg($option, $candidates); - } - $argdef = $this->getArgdef($option); - } - - if ($argdef->haveArgs) { - $minArgs = $argdef->minArgs; - $maxArgs = $argdef->maxArgs; - $values = []; - if ($value !== null) { - $values[] = $value; - $offset = 1; - } elseif ($minArgs == 0) { - # cas particulier: la premiĂšre valeur doit ĂȘtre collĂ©e Ă  l'option - # si $maxArgs == 1 - $offset = $maxArgs == 1 ? 1 : 0; - } else { - $offset = 0; - } - $this->checkEnoughArgs($option, - self::consume_args($args, $i, $values, $offset, $minArgs, $maxArgs, true)); - - if ($minArgs == 0 && $maxArgs == 1) { - # cas particulier: la premiĂšre valeur doit ĂȘtre collĂ©e Ă  l'option - if (count($values) > 0) { - $options[] = "$option=$values[0]"; - $values = array_slice($values, 1); - } else { - $options[] = $option; - } - } else { - $options[] = $option; - } - $options = array_merge($options, $values); - } elseif ($value !== null) { - throw $this->tooManyArgs(1, 0, $option); - } else { - $options[] = $option; - } - - } elseif (substr($arg, 0, 1) === "-") { - ####################################################################### - # option courte - $pos = 1; - $len = strlen($arg); - while ($pos < $len) { - $option = "-".substr($arg, $pos, 1); - $argdef = $this->getArgdef($option); - if ($argdef === null) throw $this->invalidArg($option); - if ($argdef->haveArgs) { - $minArgs = $argdef->minArgs; - $maxArgs = $argdef->maxArgs; - $values = []; - if ($len > $pos + 1) { - $values[] = substr($arg, $pos + 1); - $offset = 1; - $pos = $len; - } elseif ($minArgs == 0) { - # cas particulier: la premiĂšre valeur doit ĂȘtre collĂ©e Ă  l'option - # si $maxArgs == 1 - $offset = $maxArgs == 1 ? 1 : 0; - } else { - $offset = 0; - } - $this->checkEnoughArgs($option, - self::consume_args($args, $i, $values, $offset, $minArgs, $maxArgs, true)); - - if ($minArgs == 0 && $maxArgs == 1) { - # cas particulier: la premiĂšre valeur doit ĂȘtre collĂ©e Ă  l'option - if (count($values) > 0) { - $options[] = "$option$values[0]"; - $values = array_slice($values, 1); - } else { - $options[] = $option; - } - } else { - $options[] = $option; - } - $options = array_merge($options, $values); - } else { - $options[] = $option; - } - $pos++; - } - } else { - #XXX implĂ©menter les commandes - - ####################################################################### - # argument - $remains[] = $arg; - } - } - return array_merge($options, ["--"], $remains); - } - - function process(array $args) { - $i = 0; - $max = count($args); - # d'abord traiter les options - while ($i < $max) { - $arg = $args[$i++]; - if ($arg === "--") { - # fin des options - break; - } - - if (preg_match('/^(--[^=]+)(?:=(.*))?/', $arg, $ms)) { - # option longue - } elseif (preg_match('/^(-.)(.+)?/', $arg, $ms)) { - # option courte - } else { - # commande - throw StateException::unexpected_state("commands are not supported"); - } - $option = $ms[1]; - $ovalue = $ms[2] ?? null; - $argdef = $this->getArgdef($option); - if ($argdef === null) throw StateException::unexpected_state(); - $defvalue = $argdef->value; - if ($argdef->haveArgs) { - $minArgs = $argdef->minArgs; - $maxArgs = $argdef->maxArgs; - if ($minArgs == 0 && $maxArgs == 1) { - # argument facultatif - if ($ovalue !== null) $value = [$ovalue]; - else $value = cl::with($defvalue); - $offset = 1; - } else { - $value = []; - $offset = 0; - } - self::consume_args($args, $i, $value, $offset, $minArgs, $maxArgs, false); - } else { - $value = $defvalue; - } - - $this->action($value, $arg, $argdef); - } - - # construire la liste des arguments qui restent - $args = array_slice($args, $i); - $i = 0; - $max = count($args); - $argdef = $this->aolist->remainsArgdef; - if ($argdef !== null && $argdef->haveArgs) { - $minArgs = $argdef->minArgs; - $maxArgs = $argdef->maxArgs; - if ($maxArgs == PHP_INT_MAX) { - # cas particulier: si le nombre d'arguments restants est non bornĂ©, - # les prendre tous sans distinction ni traitement de '--' - $value = $args; - # mais tester tout de mĂȘme s'il y a le minimum requis d'arguments - $this->checkEnoughArgs(null, $minArgs - $max); - } else { - $value = []; - $this->checkEnoughArgs(null, - self::consume_args($args, $i, $value, 0, $minArgs, $maxArgs, false)); - if ($i <= $max - 1) throw $this->tooManyArgs($max, $i); - } - $this->action($value, null, $argdef); - } elseif ($i <= $max - 1) { - throw $this->tooManyArgs($max, $i); - } - } - - function action($value, ?string $arg, Aodef $argdef) { - $argdef->action($this->dest, $value, $arg, $this); - } - - public function actionPrintHelp(string $arg): void { - $this->aolist->actionPrintHelp($arg); - throw new ExitError(0); - } - - function showDebugInfos() { - echo $this->aolist."\n"; #XXX - } -} diff --git a/src/app/cli/TODO.md b/src/app/cli/TODO.md deleted file mode 100644 index eea7d89..0000000 --- a/src/app/cli/TODO.md +++ /dev/null @@ -1,21 +0,0 @@ -# cli - -* [ ] dans la section "profils", rajouter une option pour spĂ©cifier un fichier de configuration -* [ ] transformer un schĂ©ma en dĂ©finition d'arguments, un tableau en liste d'arguments, et vice-versa -* [ ] faire une implĂ©mentation ArgsParser qui supporte les commandes, et les options dynamiques - * commandes: - `program [options] command [options]` - * multi-commandes: - `program [options] command [options] // command [options] // ...` - * dynamique: la liste des options et des commandes supportĂ©es est calculĂ©e dynamiquement - -## support des commandes - -faire une interface Runnable qui reprĂ©sente un composant pouvant ĂȘtre exĂ©cutĂ©. -Application implĂ©mente Runnable, mais l'analyse des arguments peut retourner une -autre instance de runnable pour faciliter l'implĂ©mentation de diffĂ©rents -sous-outils - -## BUGS - --*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary \ No newline at end of file diff --git a/src/app/config.php b/src/app/config.php deleted file mode 100644 index 08699f9..0000000 --- a/src/app/config.php +++ /dev/null @@ -1,41 +0,0 @@ -addConfigurator($configurators); - } - - # certains types de configurations sont normalisĂ©s - /** ne configurer que le minimum pour que l'application puisse s'initialiser */ - const CONFIGURE_INITIAL_ONLY = ["include" => "initial"]; - /** ne configurer que les routes */ - const CONFIGURE_ROUTES_ONLY = ["include" => "routes"]; - /** configurer uniquement ce qui ne nĂ©cessite pas d'avoir une session */ - const CONFIGURE_NO_SESSION = ["exclude" => "session"]; - - static function configure(?array $params=null): void { - self::$config->configure($params); - } - - static final function add($config, string ...$profiles): void { self::$config->addConfig($config, $profiles); } - static final function get(string $pkey, $default=null, ?string $profile=null) { return self::$config->getValue($pkey, $default, $profile); } - static final function k(string $pkey, $default=null) { return self::$config->getValue("app.$pkey", $default); } - static final function db(string $pkey, $default=null) { return self::$config->getValue("dbs.$pkey", $default); } - static final function m(string $pkey, $default=null) { return self::$config->getValue("msgs.$pkey", $default); } - static final function l(string $pkey, $default=null) { return self::$config->getValue("mails.$pkey", $default); } -} - -new class extends config { - function __construct() { - self::$config = new ConfigManager(); - } -}; \ No newline at end of file diff --git a/src/app/config/ArrayConfig.php b/src/app/config/ArrayConfig.php deleted file mode 100644 index 6a02c8e..0000000 --- a/src/app/config/ArrayConfig.php +++ /dev/null @@ -1,50 +0,0 @@ -APP(); break; - case "dbs": $default = $this->DBS(); break; - case "msgs": $default = $this->MSGS(); break; - case "mails": $default = $this->MAILS(); break; - default: $default = []; - } - $config[$key] ??= $default; - } - $this->config = $config; - } - - protected array $config; - - function has(string $pkey, string $profile): bool { - return cl::phas($this->config, $pkey); - } - - function get(string $pkey, string $profile) { - return cl::pget($this->config, $pkey); - } - - function set(string $pkey, $value, string $profile): void { - cl::pset($this->config, $pkey, $value); - } -} diff --git a/src/app/config/ConfigManager.php b/src/app/config/ConfigManager.php deleted file mode 100644 index ef10881..0000000 --- a/src/app/config/ConfigManager.php +++ /dev/null @@ -1,150 +0,0 @@ -configurators, cl::with($configurators)); - } - - protected array $configured = []; - - /** - * configurer les objets et les classes qui ne l'ont pas encore Ă©tĂ©. la liste - * des objets et des classes Ă  configurer est fournie en appelant la mĂ©thode - * {@link addConfigurator()} - * - * par dĂ©faut, la configuration se fait en appelant toutes les mĂ©thodes - * publiques des objets et toutes les mĂ©thodes statiques des classes qui - * commencent par 'configure', e.g 'configureThis()' ou 'configure_db()', - * si elles n'ont pas dĂ©jĂ  Ă©tĂ© appelĂ©es - * - * Il est possible de modifier la liste des mĂ©thodes appelĂ©es avec le tableau - * $params, qui doit ĂȘtre conforme au schema de {@link func::CALL_ALL_SCHEMA} - */ - function configure(?array $params=null): void { - $params["prefix"] ??= "configure"; - foreach ($this->configurators as $key => $configurator) { - $configured =& $this->configured[$key]; - /** @var func[] $methods */ - $methods = func::get_all($configurator, $params); - foreach ($methods as $method) { - $name = $method->getName() ?? "(no name)"; - $done = $configured[$name] ?? false; - if (!$done) { - $method->invoke(); - $configured[$name] = true; - } - } - } - } - - ############################################################################# - - protected $cache = []; - - protected function resetCache(): void { - $this->cache = []; - } - - protected function cacheHas(string $pkey, string $profile) { - return array_key_exists("$profile.$pkey", $this->cache); - } - - protected function cacheGet(string $pkey, string $profile) { - return cl::get($this->cache, "$profile.$pkey"); - } - - protected function cacheSet(string $pkey, $value, string $profile): void { - $this->cache["$profile.$pkey"] = $value; - } - - protected array $profileConfigs = []; - - /** - * Ajouter une configuration valide pour le(s) profil(s) spĂ©cifiĂ©(s) - * - * $config est un objet ou une classe qui dĂ©finit une ou plusieurs des - * constantes APP, DBS, MSGS, MAILS - * - * si $inProfiles===null, la configuration est valide dans tous les profils - */ - function addConfig($config, ?array $inProfiles=null): void { - if (is_string($config)) { - $c = new ReflectionClass($config); - if ($c->implementsInterface(IConfig::class)) { - $config = $c->newInstance(); - } else { - $config = []; - foreach (IConfig::CONFIG_KEYS as $key) { - $config[$key] = cl::with($c->getConstant(strtoupper($key))); - } - $config = new ArrayConfig($config); - } - } elseif (is_array($config)) { - $config = new ArrayConfig($config); - } elseif (!($config instanceof IConfig)) { - throw ValueException::invalid_type($config, "array|IConfig"); - } - - $inProfiles ??= [IConfig::PROFILE_ALL]; - foreach ($inProfiles as $profile) { - $this->profileConfigs[$profile][] = $config; - } - - $this->resetCache(); - } - - function _getValue(string $pkey, $default, string $inProfile) { - $profiles = [$inProfile]; - if ($inProfile !== IConfig::PROFILE_ALL) $profiles[] = IConfig::PROFILE_ALL; - $value = $default; - foreach ($profiles as $profile) { - /** @var IConfig[] $configs */ - $configs = $this->profileConfigs[$profile] ?? []; - foreach (array_reverse($configs) as $config) { - if ($config->has($pkey, $profile)) { - $value = $config->get($pkey, $profile); - break; - } - } - } - return $value; - } - - /** - * obtenir la valeur au chemin de clĂ© $pkey dans le profil spĂ©cifiĂ© - * - * le $inProfile===null, prendre le profil par dĂ©faut. - */ - function getValue(string $pkey, $default=null, ?string $inProfile=null) { - $inProfile ??= app::get_profile(); - - if ($this->cacheHas($pkey, $inProfile)) { - return $this->cacheGet($pkey, $inProfile); - } - - $value = $this->_getValue($pkey, $default, $inProfile); - $this->cacheSet($pkey, $default, $inProfile); - return $value; - } - - function setValue(string $pkey, $value, ?string $inProfile=null): void { - $inProfile ??= app::get_profile(); - /** @var IConfig[] $configs */ - $configs =& $this->profileConfigs[$inProfile]; - if ($configs === null) $key = 0; - else $key = array_key_last($configs); - $configs[$key] ??= new ArrayConfig([]); - $configs[$key]->set($pkey, $value, $inProfile); - } -} diff --git a/src/app/config/EnvConfig.php b/src/app/config/EnvConfig.php deleted file mode 100644 index b07bf47..0000000 --- a/src/app/config/EnvConfig.php +++ /dev/null @@ -1,112 +0,0 @@ - "mysql", "name" => "mysql:host=authdb;dbname=auth;charset=utf8", - * "user" => "auth_int", "pass" => "auth" ] - * situĂ© au chemin de clĂ© dbs.auth dans le profil prod, on peut par exemple - * dĂ©finir les variables suivantes: - * CONFIG_prod_dbs__auth__type="mysql" - * CONFIG_prod_dbs__auth__name="mysql:host=authdb;dbname=auth;charset=utf8" - * CONFIG_prod_dbs__auth__user="auth_int" - * CONFIG_prod_dbs__auth__pass="auth" - * ou alternativement: - * JSON_CONFIG_prod_dbs__auth='{"type":"mysql","name":"mysql:host=authdb;dbname=auth;charset=utf8","user":"auth_int","pass":"auth"}' - * - * Les prĂ©fixes supportĂ©s sont, dans l'ordre de prĂ©cĂ©dence: - * - JSON_FILE_CONFIG -- une valeur au format JSON inscrite dans un fichier - * - JSON_CONFIG -- une valeur au format JSON - * - FILE_CONFIG -- une valeur inscrite dans un fichier - * - CONFIG -- une valeur scalaire - */ -class EnvConfig implements IConfig{ - protected ?array $profileConfigs = null; - - /** analyser $name et retourner [$pkey, $profile] */ - private static function parse_pkey_profile($name): array { - $i = strpos($name, "_"); - if ($i === false) return [false, false]; - $profile = substr($name, 0, $i); - if ($profile === "ALL") $profile = IConfig::PROFILE_ALL; - $name = substr($name, $i + 1); - $pkey = str_replace("__", ".", $name); - return [$pkey, $profile]; - } - - function loadEnvConfig(): void { - if ($this->profileConfigs !== null) return; - $json_files = []; - $jsons = []; - $files = []; - $vars = []; - foreach (getenv() as $name => $value) { - if (str::starts_with("JSON_FILE_CONFIG_", $name)) { - $json_files[str::without_prefix("JSON_FILE_CONFIG_", $name)] = $value; - } elseif (str::starts_with("JSON_CONFIG_", $name)) { - $jsons[str::without_prefix("JSON_CONFIG_", $name)] = $value; - } elseif (str::starts_with("FILE_CONFIG_", $name)) { - $files[str::without_prefix("FILE_CONFIG_", $name)] = $value; - } elseif (str::starts_with("CONFIG_", $name)) { - $vars[str::without_prefix("CONFIG_", $name)] = $value; - } - } - $profileConfigs = []; - foreach ($json_files as $name => $file) { - [$pkey, $profile] = self::parse_pkey_profile($name); - $value = json::load($file); - cl::pset($profileConfigs, "$profile.$pkey", $value); - } - foreach ($jsons as $name => $json) { - [$pkey, $profile] = self::parse_pkey_profile($name); - $value = json::decode($json); - cl::pset($profileConfigs, "$profile.$pkey", $value); - } - foreach ($files as $name => $file) { - [$pkey, $profile] = self::parse_pkey_profile($name); - $value = file::reader($file)->getContents(); - cl::pset($profileConfigs, "$profile.$pkey", $value); - } - foreach ($vars as $name => $value) { - [$pkey, $profile] = self::parse_pkey_profile($name); - cl::pset($profileConfigs, "$profile.$pkey", $value); - } - $this->profileConfigs = $profileConfigs; - } - - function has(string $pkey, string $profile): bool { - $this->loadEnvConfig(); - $config = $this->profileConfigs[$profile] ?? null; - return cl::phas($config, $pkey); - } - - function get(string $pkey, string $profile) { - $this->loadEnvConfig(); - $config = $this->profileConfigs[$profile] ?? null; - return cl::pget($config, $pkey); - } - - function set(string $pkey, $value, string $profile): void { - $this->loadEnvConfig(); - $config =& $this->profileConfigs[$profile]; - cl::pset($config, $pkey, $value); - } -} diff --git a/src/app/config/IConfig.php b/src/app/config/IConfig.php deleted file mode 100644 index dcba89f..0000000 --- a/src/app/config/IConfig.php +++ /dev/null @@ -1,24 +0,0 @@ - true, - "test" => true, - ]; - - /** - * @var array mapping profil d'application --> profil effectif - * - * ce mapping est utilisĂ© quand il faut calculer le profil courant s'il n'a - * pas Ă©tĂ© spĂ©cifiĂ© par l'utilisateur. il permet de faire correspondre le - * profil courant de l'application avec le profil effectif Ă  sĂ©lectionner - */ - const PROFILE_MAP = null; - - function __construct(?array $params=null) { - $this->isAppProfile = $params["app"] ?? false; - $this->profiles = static::PROFILES; - $this->productionModes = static::PRODUCTION_MODES; - $this->profileMap = static::PROFILE_MAP; - $name = $params["name"] ?? static::NAME; - if ($name === null) { - $this->configKey = null; - $this->envKeys = ["APP_PROFILE"]; - } else { - $configKey = "${name}_profile"; - $envKey = strtoupper($configKey); - if ($this->isAppProfile) { - $this->configKey = null; - $this->envKeys = [$envKey, "APP_PROFILE"]; - } else { - $this->configKey = $configKey; - $this->envKeys = [$envKey]; - } - } - $this->defaultProfile = $params["default_profile"] ?? null; - $profile = $params["profile"] ?? null; - $productionMode = $params["production_mode"] ?? null; - $productionMode ??= $this->productionModes[$profile] ?? false; - $this->profile = $profile; - $this->productionMode = $productionMode; - } - - /** - * @var bool cet objet est-il utilisĂ© pour gĂ©rer le profil de l'application? - */ - protected bool $isAppProfile; - - protected ?array $profiles; - - protected ?array $productionModes; - - protected ?array $profileMap; - - protected function mapProfile(?string $profile): ?string { - return $this->profileMap[$profile] ?? $profile; - } - - protected ?string $configKey; - - function getConfigProfile(): ?string { - if ($this->configKey === null) return null; - return config::k($this->configKey); - } - - protected array $envKeys; - - function getEnvProfile(): ?string { - foreach ($this->envKeys as $envKey) { - $profile = getenv($envKey); - if ($profile !== false) return $profile; - } - return null; - } - - protected ?string $defaultProfile; - - function getDefaultProfile(): ?string { - return $this->defaultProfile; - } - - function setDefaultProfile(?string $profile): void { - $this->defaultProfile = $profile; - } - - protected ?string $profile; - - protected bool $productionMode; - - protected function resolveProfile(): void { - $profile ??= $this->getenvProfile(); - $profile ??= $this->getConfigProfile(); - $profile ??= $this->getDefaultProfile(); - if ($this->isAppProfile) { - $profile ??= $this->profiles[0] ?? "prod"; - } else { - $profile ??= $this->mapProfile(app::get_profile()); - } - $this->profile = $profile; - $this->productionMode = $this->productionModes[$profile] ?? false; - } - - function getProfile(?bool &$productionMode=null): string { - if ($this->profile === null) $this->resolveProfile(); - $productionMode = $this->productionMode; - return $this->profile; - } - - function isProductionMode(): bool { - return $this->productionMode; - } - - function setProfile(?string $profile=null, ?bool $productionMode=null): void { - if ($profile === null) $this->profile = null; - $profile ??= $this->getProfile($productionMode); - $productionMode ??= $this->productionModes[$profile] ?? false; - $this->profile = $profile; - $this->productionMode = $productionMode; - } -} diff --git a/src/app/config/YamlConfig.php b/src/app/config/YamlConfig.php deleted file mode 100644 index e248c9c..0000000 --- a/src/app/config/YamlConfig.php +++ /dev/null @@ -1,13 +0,0 @@ -|<|>|<=|>=|(?:is\s+)?null|(?:is\s+)?not\s+null)\s*(.*)$/', $arg, $ms); - } - - protected function storageCtl(CapacitorStorage $storage): void { - $args = $this->args; - - $channelClass = $this->channelClass; - $tableName = $this->tableName; - if ($channelClass === null && $tableName === null) { - $name = A::shift($args); - if ($name !== null) { - if (!$storage->channelExists($name, $row)) { - self::die("$name: nom de canal de donnĂ©es introuvable"); - } - if ($row["class_name"] !== "class@anonymous") $channelClass = $row["class_name"]; - else $tableName = $row["table_name"]; - } - } - if ($channelClass !== null) { - $channelClass = str_replace("/", "\\", $channelClass); - $channel = new $channelClass; - } elseif ($tableName !== null) { - $channel = new class($tableName) extends CapacitorChannel { - function __construct(?string $name=null) { - parent::__construct($name); - $this->tableName = $name; - } - }; - } else { - $found = false; - foreach ($storage->getChannels() as $row) { - msg::print($row["name"]); - $found = true; - } - if ($found) self::exit(); - self::die("Vous devez spĂ©cifier le canal de donnĂ©es"); - } - $capacitor = new Capacitor($storage, $channel); - - switch ($this->action) { - case self::ACTION_RESET: - $capacitor->reset($this->recreate); - break; - case self::ACTION_QUERY: - if (!$args) { - # lister les id - $out = new Stream(STDOUT); - $primaryKeys = $storage->getPrimaryKeys($channel); - $rows = $storage->db()->all([ - "select", - "cols" => $primaryKeys, - "from" => $channel->getTableName(), - ]); - $out->fputcsv($primaryKeys); - foreach ($rows as $row) { - $rowIds = $storage->getRowIds($channel, $row); - $out->fputcsv($rowIds); - } - } else { - # afficher les lignes correspondantes - if (count($args) == 1 && !self::isa_cond($args[0])) { - $filter = $args[0]; - } else { - $filter = []; - $ms = null; - foreach ($args as $arg) { - if (self::isa_cond($arg, $ms)) { - $filter[$ms[1]] = [$ms[2], $ms[3]]; - } else { - $filter[$arg] = ["not null"]; - } - } - } - $first = true; - $capacitor->each($filter, function ($row) use (&$first) { - if ($first) $first = false; - else echo "---\n"; - yaml::dump($row); - }); - } - break; - case self::ACTION_SQL: - echo $capacitor->getCreateSql()."\n"; - break; - } - } -} diff --git a/src/cli/BgLauncherApp.php b/src/cli/BgLauncherApp.php deleted file mode 100644 index e831e78..0000000 --- a/src/cli/BgLauncherApp.php +++ /dev/null @@ -1,124 +0,0 @@ - "lancer un script en tĂąche de fond", - "usage" => "ApplicationClass args...", - - "sections" => [ - parent::VERBOSITY_SECTION, - ], - - ["-i", "--infos", "name" => "action", "value" => self::ACTION_INFOS, - "help" => "Afficher des informations sur la tĂąche", - ], - ["-s", "--start", "name" => "action", "value" => self::ACTION_START, - "help" => "DĂ©marrer la tĂąche", - ], - ["-k", "--stop", "name" => "action", "value" => self::ACTION_STOP, - "help" => "ArrĂȘter la tĂąche", - ], - ]; - - protected int $action = self::ACTION_START; - - protected ?array $args = null; - - static function show_infos(RunFile $runfile, ?int $level=null): void { - msg::print($runfile->getDesc(), $level); - msg::print(yaml::with(["data" => $runfile->read()]), ($level ?? 0) - 1); - } - - function main() { - $args = $this->args; - - $appClass = $args[0] ?? null; - if ($appClass === null) { - self::die("Vous devez spĂ©cifier la classe de l'application"); - } - $appClass = $args[0] = str_replace("/", "\\", $appClass); - if (!class_exists($appClass)) { - self::die("$appClass: classe non trouvĂ©e"); - } - - $useRunfile = constant("$appClass::USE_RUNFILE"); - if (!$useRunfile) { - self::die("Cette application ne supporte le lancement en tĂąche de fond"); - } - - $runfile = app::with($appClass)->getRunfile(); - switch ($this->action) { - case self::ACTION_START: - $argc = count($args); - $appClass::_manage_runfile($argc, $args, $runfile); - if ($runfile->warnIfLocked()) self::exit(app::EC_LOCKED); - array_splice($args, 0, 0, [ - PHP_BINARY, - path::abspath(NULIB_APP_app_launcher), - ]); - app::params_putenv(); - self::_start($args, $runfile); - break; - case self::ACTION_STOP: - self::_stop($runfile); - self::show_infos($runfile, -1); - break; - case self::ACTION_INFOS: - self::show_infos($runfile); - break; - } - } - - public static function _start(array $args, Runfile $runfile): void { - $pid = pcntl_fork(); - if ($pid == -1) { - # parent, impossible de forker - throw new ExitError(app::EC_FORK_PARENT, "Unable to fork"); - } elseif (!$pid) { - # child, fork ok - $runfile->wfPrepare($pid); - $outfile = $runfile->getOutfile() ?? "/tmp/NULIB_APP_app_console.out"; - $exitcode = app::EC_FORK_CHILD; - try { - # rediriger STDIN, STDOUT et STDERR - fclose(fopen($outfile, "wb")); // vider le fichier - fclose(STDIN); $in = fopen("/dev/null", "rb"); - fclose(STDOUT); $out = fopen($outfile, "ab"); - fclose(STDERR); $err = fopen($outfile, "ab"); - # puis lancer la commande - $cmd = new Cmd($args); - $cmd->addSource("/g/init.env"); - $cmd->addRedir("both", $outfile, true); - $cmd->fork_exec($exitcode, false); - sh::_waitpid(-$pid, $exitcode); - } finally { - $runfile->wfReaped($exitcode); - } - } - } - - public static function _stop(Runfile $runfile): bool { - $data = $runfile->read(); - $pid = $runfile->_getCid($data); - msg::action("stop $pid"); - if ($runfile->wfKill($reason)) { - msg::asuccess(); - return true; - } else { - msg::afailure($reason); - return false; - } - } -} diff --git a/src/cli/DumpserApp.php b/src/cli/DumpserApp.php deleted file mode 100644 index 12c8d24..0000000 --- a/src/cli/DumpserApp.php +++ /dev/null @@ -1,33 +0,0 @@ - parent::ARGS, - "purpose" => "afficher des donnĂ©es sĂ©rialisĂ©es", - ]; - - protected $args; - - function main() { - $files = []; - foreach ($this->args as $arg) { - if (is_file($arg)) { - $files[] = $arg; - } else { - msg::warning("$arg: fichier invalide ou introuvable"); - } - } - $showSection = count($files) > 1; - foreach ($files as $file) { - if ($showSection) msg::section($file); - $sfile = new SharedFile($file); - yaml::dump($sfile->unserialize()); - } - } -} diff --git a/src/cli/Json2yamlApp.php b/src/cli/Json2yamlApp.php deleted file mode 100644 index 237c17e..0000000 --- a/src/cli/Json2yamlApp.php +++ /dev/null @@ -1,23 +0,0 @@ -args[0] ?? null; - if ($input === null || $input === "-") { - $output = null; - } else { - $output = path::ensure_ext($input, ".yml", ".json"); - } - - $data = json::load($input); - yaml::dump($data, $output); - } -} \ No newline at end of file diff --git a/src/cli/MysqlStorageApp.php b/src/cli/MysqlStorageApp.php deleted file mode 100644 index 6f28225..0000000 --- a/src/cli/MysqlStorageApp.php +++ /dev/null @@ -1,45 +0,0 @@ - parent::ARGS, - "purpose" => "gestion d'un capacitor mysql", - "usage" => [ - "DBCONN [CHANNEL_NAME | -t TABLE | -c CHANNEL_CLASS] [--query] key=value...", - "DBCONN [CHANNEL_NAME | -t TABLE | -c CHANNEL_CLASS] --sql-create", - ], - ["-t", "--table-name", "args" => 1, - "help" => "nom de la table porteuse du canal de donnĂ©es", - ], - ["-c", "--channel-class", "args" => 1, - "help" => "nom de la classe dĂ©rivĂ©e de CapacitorChannel", - ], - ["-z", "--reset", "name" => "action", "value" => self::ACTION_RESET, - "help" => "rĂ©initialiser le canal", - ], - ["-n", "--no-recreate", "name" => "recreate", "value" => false, - "help" => "ne pas recrĂ©er la table correspondant au canal" - ], - ["--query", "name" => "action", "value" => self::ACTION_QUERY, - "help" => "lister les lignes correspondant aux valeurs spĂ©cifiĂ©es. c'est l'action par dĂ©faut", - ], - ["-s", "--sql-create", "name" => "action", "value" => self::ACTION_SQL, - "help" => "afficher la requĂȘte pour crĂ©er la table", - ], - ]; - - function main() { - $dbconn = A::shift($this->args); - if ($dbconn === null) self::die("Vous devez spĂ©cifier la base de donnĂ©es"); - $tmp = config::db($dbconn); - if ($tmp === null) self::die("$dbconn: base de donnĂ©es invalide"); - $storage = new MysqlStorage($tmp); - - $this->storageCtl($storage); - } -} diff --git a/src/cli/PgsqlStorageApp.php b/src/cli/PgsqlStorageApp.php deleted file mode 100644 index c10bfde..0000000 --- a/src/cli/PgsqlStorageApp.php +++ /dev/null @@ -1,45 +0,0 @@ - parent::ARGS, - "purpose" => "gestion d'un capacitor pgsql", - "usage" => [ - "DBCONN [CHANNEL_NAME | -t TABLE | -c CHANNEL_CLASS] [--query] key=value...", - "DBCONN [CHANNEL_NAME | -t TABLE | -c CHANNEL_CLASS] --sql-create", - ], - ["-t", "--table-name", "args" => 1, - "help" => "nom de la table porteuse du canal de donnĂ©es", - ], - ["-c", "--channel-class", "args" => 1, - "help" => "nom de la classe dĂ©rivĂ©e de CapacitorChannel", - ], - ["-z", "--reset", "name" => "action", "value" => self::ACTION_RESET, - "help" => "rĂ©initialiser le canal", - ], - ["-n", "--no-recreate", "name" => "recreate", "value" => false, - "help" => "ne pas recrĂ©er la table correspondant au canal" - ], - ["--query", "name" => "action", "value" => self::ACTION_QUERY, - "help" => "lister les lignes correspondant aux valeurs spĂ©cifiĂ©es. c'est l'action par dĂ©faut", - ], - ["-s", "--sql-create", "name" => "action", "value" => self::ACTION_SQL, - "help" => "afficher la requĂȘte pour crĂ©er la table", - ], - ]; - - function main() { - $dbconn = A::shift($this->args); - if ($dbconn === null) self::die("Vous devez spĂ©cifier la base de donnĂ©es"); - $tmp = config::db($dbconn); - if ($tmp === null) self::die("$dbconn: base de donnĂ©es invalide"); - $storage = new PgsqlStorage($tmp); - - $this->storageCtl($storage); - } -} diff --git a/src/cli/SqliteStorageApp.php b/src/cli/SqliteStorageApp.php deleted file mode 100644 index 357099d..0000000 --- a/src/cli/SqliteStorageApp.php +++ /dev/null @@ -1,43 +0,0 @@ - parent::ARGS, - "purpose" => "gestion d'un capacitor sqlite", - "usage" => [ - "DBFILE [CHANNEL_NAME | -t TABLE | -c CHANNEL_CLASS] [--query] key=value...", - "DBFILE [CHANNEL_NAME | -t TABLE | -c CHANNEL_CLASS] --sql-create", - ], - ["-t", "--table-name", "args" => 1, - "help" => "nom de la table porteuse du canal de donnĂ©es", - ], - ["-c", "--channel-class", "args" => 1, - "help" => "nom de la classe dĂ©rivĂ©e de CapacitorChannel", - ], - ["-z", "--reset", "name" => "action", "value" => self::ACTION_RESET, - "help" => "rĂ©initialiser le canal", - ], - ["-n", "--no-recreate", "name" => "recreate", "value" => false, - "help" => "ne pas recrĂ©er la table correspondant au canal" - ], - ["--query", "name" => "action", "value" => self::ACTION_QUERY, - "help" => "lister les lignes correspondant aux valeurs spĂ©cifiĂ©es. c'est l'action par dĂ©faut", - ], - ["-s", "--sql-create", "name" => "action", "value" => self::ACTION_SQL, - "help" => "afficher la requĂȘte pour crĂ©er la table", - ], - ]; - - function main() { - $dbfile = A::shift($this->args); - if ($dbfile === null) self::die("Vous devez spĂ©cifier la base de donnĂ©es"); - if (!file_exists($dbfile)) self::die("$dbfile: fichier introuvable"); - $storage = new SqliteStorage($dbfile); - - $this->storageCtl($storage); - } -} diff --git a/src/cli/SteamTrainApp.php b/src/cli/SteamTrainApp.php deleted file mode 100644 index c24a64d..0000000 --- a/src/cli/SteamTrainApp.php +++ /dev/null @@ -1,53 +0,0 @@ - self::TITLE, - "description" => << 1, - "help" => "spĂ©cifier le nombre d'Ă©tapes", - ], - ["-f", "--force-enabled", "value" => true, - "help" => "lancer la commande mĂȘme si les tĂąches planifiĂ©es sont dĂ©sactivĂ©es", - ], - ["-n", "--no-install-signal-handler", "value" => false, - "help" => "ne pas installer le gestionnaire de signaux", - ], - ]; - - protected $count = 100; - - protected bool $forceEnabled = false; - - protected bool $installSignalHandler = true; - - function main() { - app::check_bgapplication_enabled($this->forceEnabled); - if ($this->installSignalHandler) app::install_signal_handler(); - $count = intval($this->count); - msg::info("Starting train for ".words::q($count, "step#s")); - app::action("Running train...", $count); - for ($i = 1; $i <= $count; $i++) { - msg::print("Tchou-tchou! x $i"); - app::step(); - sleep(1); - } - msg::info("Stopping train at ".new DateTime()); - } -} diff --git a/src/cli/Yaml2jsonApp.php b/src/cli/Yaml2jsonApp.php deleted file mode 100644 index 0cd4541..0000000 --- a/src/cli/Yaml2jsonApp.php +++ /dev/null @@ -1,23 +0,0 @@ -args[0] ?? null; - if ($input === null || $input === "-") { - $output = null; - } else { - $output = path::ensure_ext($input, ".json", [".yml", ".yaml"]); - } - - $data = yaml::load($input); - json::dump($data, $output); - } -} \ No newline at end of file diff --git a/src/php/types/varray.php b/src/php/types/varray.php deleted file mode 100644 index bc46388..0000000 --- a/src/php/types/varray.php +++ /dev/null @@ -1,24 +0,0 @@ - $projdir, - "vendor" => [ - "bindir" => "$projdir/vendor/bin", - "autoload" => "$projdir/vendor/autoload.php", - ], - "appcode" => "nur-ture", - "cwd" => $cwd, - "datadir" => "$projdir/devel", - "etcdir" => "$projdir/devel/etc", - "vardir" => "$projdir/devel/var", - "logdir" => "$projdir/devel/log", - "profile" => "devel", - "appgroup" => null, - "name" => "my-application1", - "title" => null, - ], $app1->getParams()); - - $app2 = myapp::with(MyApplication2::class, $app1); - self::assertSame([ - "projdir" => $projdir, - "vendor" => [ - "bindir" => "$projdir/vendor/bin", - "autoload" => "$projdir/vendor/autoload.php", - ], - "appcode" => "nur-ture", - "cwd" => $cwd, - "datadir" => "$projdir/devel", - "etcdir" => "$projdir/devel/etc", - "vardir" => "$projdir/devel/var", - "logdir" => "$projdir/devel/log", - "profile" => "devel", - "appgroup" => null, - "name" => "my-application2", - "title" => null, - ], $app2->getParams()); - } - - function testInit() { - $projdir = config::get_projdir(); - $cwd = getcwd(); - - myapp::reset(); - myapp::init(MyApplication1::class); - self::assertSame([ - "projdir" => $projdir, - "vendor" => [ - "bindir" => "$projdir/vendor/bin", - "autoload" => "$projdir/vendor/autoload.php", - ], - "appcode" => "nur-ture", - "cwd" => $cwd, - "datadir" => "$projdir/devel", - "etcdir" => "$projdir/devel/etc", - "vardir" => "$projdir/devel/var", - "logdir" => "$projdir/devel/log", - "profile" => "devel", - "appgroup" => null, - "name" => "my-application1", - "title" => null, - ], myapp::get()->getParams()); - - myapp::init(MyApplication2::class); - self::assertSame([ - "projdir" => $projdir, - "vendor" => [ - "bindir" => "$projdir/vendor/bin", - "autoload" => "$projdir/vendor/autoload.php", - ], - "appcode" => "nur-ture", - "cwd" => $cwd, - "datadir" => "$projdir/devel", - "etcdir" => "$projdir/devel/etc", - "vardir" => "$projdir/devel/var", - "logdir" => "$projdir/devel/log", - "profile" => "devel", - "appgroup" => null, - "name" => "my-application2", - "title" => null, - ], myapp::get()->getParams()); - } - } -} - -namespace nulib\app\impl { - - use nulib\app\cli\Application; - use nulib\os\path; - use nulib\app\app; - - class config { - const PROJDIR = __DIR__.'/../..'; - - static function get_projdir(): string { - return path::abspath(self::PROJDIR); - } - } - - class myapp extends app { - static function reset(): void { - self::$app = null; - } - } - - class MyApplication1 extends Application { - const PROJDIR = config::PROJDIR; - - function main() { - } - } - class MyApplication2 extends Application { - const PROJDIR = null; - - function main() { - } - } -} diff --git a/tests/app/cli/AodefTest.php b/tests/app/cli/AodefTest.php deleted file mode 100644 index 43fa16a..0000000 --- a/tests/app/cli/AodefTest.php +++ /dev/null @@ -1,158 +0,0 @@ -setup1(); - $aodef->setup2(); - #var_export($aodef->debugInfos()); #XXX - self::assertSame($options, $aodef->getOptions()); - self::assertSame($haveShortOptions, $aodef->haveShortOptions, "haveShortOptions"); - self::assertSame($haveLongOptions, $aodef->haveLongOptions, "haveLongOptions"); - self::assertSame($isCommand, $aodef->isCommand, "isCommand"); - self::assertSame($haveArgs, $aodef->haveArgs, "haveArgs"); - self::assertSame($minArgs, $aodef->minArgs, "minArgs"); - self::assertSame($maxArgs, $aodef->maxArgs, "maxArgs"); - self::assertSame($argsdesc, $aodef->argsdesc, "argsdesc"); - } - - function testArgsNone() { - $aodef = new Aodef(["-o"]); - self::assertArg($aodef, - ["-o"], - true, false, false, - false, 0, 0, ""); - - $aodef = new Aodef(["--longo"]); - self::assertArg($aodef, - ["--longo"], - false, true, false, - false, 0, 0, ""); - - $aodef = new Aodef(["-o", "--longo"]); - self::assertArg($aodef, - ["-o", "--longo"], - true, true, false, - false, 0, 0, ""); - } - - function testArgsMandatory() { - $aodef = new Aodef(["-o:", "--longo"]); - self::assertArg($aodef, - ["-o", "--longo"], - true, true, false, - true, 1, 1, "VALUE"); - - $aodef = new Aodef(["-a:", "-b:"]); - self::assertArg($aodef, - ["-a", "-b"], - true, false, false, - true, 1, 1, "VALUE"); - - $aodef = new Aodef(["-a:", "-b::"]); - self::assertArg($aodef, - ["-a", "-b"], - true, false, false, - true, 1, 1, "VALUE"); - - $aodef = new Aodef(["-a::", "-b:"]); - self::assertArg($aodef, - ["-a", "-b"], - true, false, false, - true, 1, 1, "VALUE"); - - $aodef = new Aodef(["-o", "--longo", "args" => true]); - self::assertArg($aodef, - ["-o", "--longo"], - true, true, false, - true, 1, 1, "VALUE"); - - $aodef = new Aodef(["-o", "--longo", "args" => 1]); - self::assertArg($aodef, - ["-o", "--longo"], - true, true, false, - true, 1, 1, "VALUE"); - - $aodef = new Aodef(["-o", "--longo", "args" => "value"]); - self::assertArg($aodef, - ["-o", "--longo"], - true, true, false, - true, 1, 1, "VALUE"); - - $aodef = new Aodef(["-o", "--longo", "args" => ["value"]]); - self::assertArg($aodef, - ["-o", "--longo"], - true, true, false, - true, 1, 1, "VALUE"); - } - - function testArgsOptional() { - $aodef = new Aodef(["-o::", "--longo"]); - self::assertArg($aodef, - ["-o", "--longo"], - true, true, false, - true, 0, 1, "[VALUE]"); - - $aodef = new Aodef(["-o", "--longo", "args" => [["value"]]]); - self::assertArg($aodef, - ["-o", "--longo"], - true, true, false, - true, 0, 1, "[VALUE]"); - - $aodef = new Aodef(["-o", "--longo", "args" => [[null]]]); - self::assertArg($aodef, - ["-o", "--longo"], - true, true, false, - true, 0, PHP_INT_MAX, "[VALUEs...]"); - - $aodef = new Aodef(["-o", "--longo", "args" => ["value", null]]); - self::assertArg($aodef, - ["-o", "--longo"], - true, true, false, - true, 1, PHP_INT_MAX, "VALUE [VALUEs...]"); - - $aodef = new Aodef(["-o", "--longo", "args" => "*"]); - self::assertArg($aodef, - ["-o", "--longo"], - true, true, false, - true, 0, PHP_INT_MAX, "[VALUEs...]"); - - $aodef = new Aodef(["-o", "--longo", "args" => "+"]); - self::assertArg($aodef, - ["-o", "--longo"], - true, true, false, - true, 1, PHP_INT_MAX, "VALUE [VALUEs...]"); - } - - function testMerge() { - $BASE = ["-o:", "--longo"]; - - $aodef = new Aodef([ - "merge" => $BASE, - "add" => ["-a", "--longa"], - "remove" => ["-o", "--longo"], - ]); - self::assertArg($aodef, - ["-a", "--longa"], - true, true, false, - false, 0, 0, ""); - - $aodef = new Aodef([ - "merge" => $BASE, - "add" => ["-a", "--longa"], - "remove" => ["-o", "--longo"], - "-x", - ]); - self::assertArg($aodef, - ["-a", "--longa", "-x"], - true, true, false, - false, 0, 0, ""); - } -} diff --git a/tests/app/cli/AolistTest.php b/tests/app/cli/AolistTest.php deleted file mode 100644 index 863edc4..0000000 --- a/tests/app/cli/AolistTest.php +++ /dev/null @@ -1,60 +0,0 @@ - "value", - ["--opt"], - ["group", - ["--gopt1"], - ["--gopt2"], - ], - "sections" => [ - [ - ["--s0opt"], - ["group", - ["--s0gopt1"], - ["--s0gopt2"], - ], - ], - "ns" => [ - ["--nsopt"], - ["group", - ["--nsgopt1"], - ["--nsgopt2"], - ], - ], - ], - ]) extends Aolist {}; - - echo "$aolist\n"; - self::assertTrue(true); - } -} diff --git a/tests/app/cli/SimpleAolistTest.php b/tests/app/cli/SimpleAolistTest.php deleted file mode 100644 index ed67a79..0000000 --- a/tests/app/cli/SimpleAolistTest.php +++ /dev/null @@ -1,58 +0,0 @@ - [ - ["-o", "--longo"], - ], - ]); - echo "$aolist\n"; #XXX - - $aolist = new SimpleAolist([ - ["-o", "--longo"], - ["-o", "--longx"], - ]); - echo "$aolist\n"; #XXX - - $aolist = new SimpleAolist([ - ["-o", "--longo"], - ["-o"], - ["--longo"], - ]); - echo "$aolist\n"; #XXX - - self::assertTrue(true); - } - - function testExtends() { - $ARGS0 = [ - ["-o:", "--longo", - "name" => "desto", - "help" => "help longo" - ], - ["-a:", "--longa", - "name" => "desta", - "help" => "help longa" - ], - ]; - $ARGS = [ - "merge" => $ARGS0, - ["extends" => "-a", - "remove" => ["--longa"], - "add" => ["--desta"], - "help" => "help desta" - ], - ]; - //$aolist0 = new SimpleArgDefs($ARGS0); - //echo "$aolist0\n"; #XXX - $aolist = new SimpleAolist($ARGS); - echo "$aolist\n"; #XXX - - self::assertTrue(true); - } -} diff --git a/tests/app/cli/SimpleArgsParserTest.php b/tests/app/cli/SimpleArgsParserTest.php deleted file mode 100644 index aa11c56..0000000 --- a/tests/app/cli/SimpleArgsParserTest.php +++ /dev/null @@ -1,174 +0,0 @@ - [["value", "value"]]], - ["--mo12:", "args" => ["value", ["value"]]], - ["--mo22:", "args" => ["value", "value"]], - ]; - const NORMALIZE_TESTS = [ - [], ["--"], - ["--"], ["--"], - ["--", "--"], ["--", "--"], - ["-aa"], ["-a", "-a", "--"], - ["a", "b"], ["--", "a", "b"], - ["-a", "--ma", "x", "a", "--ma=y", "b"], ["-a", "--mandatory", "x", "--mandatory", "y", "--", "a", "b"], - ["-mx", "-m", "y"], ["-m", "x", "-m", "y", "--"], - ["-ox", "-o", "y"], ["-ox", "-o", "--", "y"], - ["-a", "--", "-a", "-c"], ["-a", "--", "-a", "-c"], - - # -a et -b doivent ĂȘtre considĂ©rĂ©s comme arguments, -n comme option - ["--mo02"], ["--mo02", "--", "--"], - ["--mo02", "-a"], ["--mo02", "-a", "--", "--"], - ["--mo02", "--"], ["--mo02", "--", "--"], - ["--mo02", "--", "-n"], ["--mo02", "--", "-n", "--"], - ["--mo02", "--", "--", "-b"], ["--mo02", "--", "--", "-b"], - # - ["--mo02", "-a"], ["--mo02", "-a", "--", "--"], - ["--mo02", "-a", "-a"], ["--mo02", "-a", "-a", "--"], - ["--mo02", "-a", "--"], ["--mo02", "-a", "--", "--"], - ["--mo02", "-a", "--", "-n"], ["--mo02", "-a", "--", "-n", "--"], - ["--mo02", "-a", "--", "--", "-b"], ["--mo02", "-a", "--", "--", "-b"], - - [ - "--mo02", "--", - "--mo02", "x", "--", - "--mo02", "x", "y", - "--mo12", "x", "--", - "--mo12", "x", "y", - "--mo22", "x", "y", - "z", - ], [ - "--mo02", "--", - "--mo02", "x", "--", - "--mo02", "x", "y", - "--mo12", "x", "--", - "--mo12", "x", "y", - "--mo22", "x", "y", - "--", - "z", - ], - ]; - - function testNormalize() { - $parser = new SimpleArgsParser(self::NORMALIZE_ARGS); - $count = count(self::NORMALIZE_TESTS); - for ($i = 0; $i < $count; $i += 2) { - $args = self::NORMALIZE_TESTS[$i]; - $expected = self::NORMALIZE_TESTS[$i + 1]; - $normalized = $parser->normalize($args); - self::assertSame($expected, $normalized - , "for ".var_export($args, true) - .", normalized is ".var_export($normalized, true) - ); - } - } - - function testArgsNone() { - $parser = new SimpleArgsParser([ - ["-z"], - ["-a"], - ["-b"], - ["-c",], - ["-d", "value" => 42], - ]); - - $dest = []; $parser->parse($dest, ["-a", "-bb", "-ccc", "-dddd"]); - self::assertSame(null, $dest["z"] ?? null); - self::assertSame(1, $dest["a"] ?? null); - self::assertSame(2, $dest["b"] ?? null); - self::assertSame(3, $dest["c"] ?? null); - self::assertSame(42, $dest["d"] ?? null); - - self::assertTrue(true); - } - - function testArgsMandatory() { - $parser = new SimpleArgsParser([ - ["-z:"], - ["-a:"], - ["-b:"], - ["-c:", "value" => 42], - ]); - - $dest = []; $parser->parse($dest, [ - "-a", - "-bb", - "-c", - "-c15", - "-c30", - "-c45", - ]); - self::assertSame(null, $dest["z"] ?? null); - self::assertSame("-bb", $dest["a"] ?? null); - self::assertSame(null, $dest["b"] ?? null); - self::assertSame("45", $dest["c"] ?? null); - - self::assertTrue(true); - } - - function testArgsOptional() { - $parser = new SimpleArgsParser([ - ["-z::"], - ["-a::"], - ["-b::"], - ["-c::", "value" => 42], - ["-d::", "value" => 42], - ]); - - $dest = []; $parser->parse($dest, [ - "-a", - "-bb", - "-c", - "-d15", - "-d30", - ]); - self::assertSame(null, $dest["z"] ?? null); - self::assertSame(null, $dest["a"] ?? null); - self::assertSame("b", $dest["b"] ?? null); - self::assertSame(42, $dest["c"] ?? null); - self::assertSame("30", $dest["d"] ?? null); - - self::assertTrue(true); - } - - function testRemains() { - $parser = new SimpleArgsParser([]); - $dest = []; $parser->parse($dest, ["x", "y"]); - self::assertSame(["x", "y"], $dest["args"] ?? null); - } - - function test() { - $parser = new SimpleArgsParser([ - ["-n", "--none"], - ["-m:", "--mandatory"], - ["-o::", "--optional"], - ["--mo02:", "args" => [["value", "value"]]], - ["--mo12:", "args" => ["value", ["value"]]], - ["--mo22:", "args" => ["value", "value"]], - ]); - $parser->parse($dest, [ - "--mo02", "--", - "--mo02", "x", "--", - "--mo02", "x", "y", - "--mo12", "x", "--", - "--mo12", "x", "y", - "--mo22", "x", "y", - "z", - ]); - - self::assertTrue(true); - } -} diff --git a/tests/app/config/ConfigManagerTest.php b/tests/app/config/ConfigManagerTest.php deleted file mode 100644 index 69ba5f8..0000000 --- a/tests/app/config/ConfigManagerTest.php +++ /dev/null @@ -1,124 +0,0 @@ -addConfigurator(config1::class); - $config->configure(); - self::assertSame([ - "config1::static configure1", - ], impl\result::$configured); - - result::reset(); - $config->addConfigurator(config1::class); - $config->configure(); - $config->configure(); - $config->configure(); - self::assertSame([ - "config1::static configure1", - ], impl\result::$configured); - - result::reset(); - $config->addConfigurator(new config1()); - $config->configure(); - self::assertSame([ - "config1::static configure1", - "config1::configure2", - ], impl\result::$configured); - - result::reset(); - $config->addConfigurator(new config1()); - $config->configure(["include" => "2"]); - self::assertSame([ - "config1::configure2", - ], impl\result::$configured); - $config->configure(["include" => "1"]); - self::assertSame([ - "config1::configure2", - "config1::static configure1", - ], impl\result::$configured); - - result::reset(); - $config->addConfigurator([ - config1::class, - new config2(), - ]); - $config->configure(); - self::assertSame([ - "config1::static configure1", - "config2::static configure1", - "config2::configure2", - ], impl\result::$configured); - } - - function testConfig() { - $config = new ConfigManager(); - - $config->addConfig([ - "app" => [ - "var" => "array", - ] - ]); - self::assertSame("array", $config->getValue("app.var")); - - $config->addConfig(new ArrayConfig([ - "app" => [ - "var" => "instance", - ] - ])); - self::assertSame("instance", $config->getValue("app.var")); - - $config->addConfig(config1::class); - self::assertSame("class1", $config->getValue("app.var")); - - $config->addConfig(config2::class); - self::assertSame("class2", $config->getValue("app.var")); - } - } -} - -namespace nulib\app\config\impl { - class result { - static array $configured = []; - - static function reset() { - self::$configured = []; - } - } - - class config1 { - const APP = [ - "var" => "class1", - ]; - - static function configure1() { - result::$configured[] = "config1::static configure1"; - } - - function configure2() { - result::$configured[] = "config1::configure2"; - } - } - - class config2 { - const APP = [ - "var" => "class2", - ]; - - static function configure1() { - result::$configured[] = "config2::static configure1"; - } - - function configure2() { - result::$configured[] = "config2::configure2"; - } - } -}