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";
- }
- }
-}