diff --git a/skeleton-test.php b/skeleton-test.php
deleted file mode 100644
index 59fbbb7e..00000000
--- a/skeleton-test.php
+++ /dev/null
@@ -1,28 +0,0 @@
-addDependency('bar')
- ->addStaticLib('libfoo.a', 'unix')
- ->addStaticLib('libfoo.a', 'unix')
- ->addArtifact($artifact_generator = new ArtifactGenerator('foo')->setSource(['type' => 'url', 'url' => 'https://example.com/foo.tar.gz']))
- ->enableBuild(['Darwin', 'Linux'], 'build')
- ->addFunctionExecutorBinding('build', new ExecutorGenerator(UnixCMakeExecutor::class));
-
-$pkg_config = $package_generator->generateConfigArray();
-$artifact_config = $artifact_generator->generateConfigArray();
-
-echo '===== pkg.json =====' . PHP_EOL;
-echo json_encode($pkg_config, 64 | 128 | 256) . PHP_EOL;
-echo '===== artifact.json =====' . PHP_EOL;
-echo json_encode($artifact_config, 64 | 128 | 256) . PHP_EOL;
-echo '===== php code for package =====' . PHP_EOL;
-echo $package_generator->generatePackageClassFile('Package\Library');
diff --git a/src/StaticPHP/Command/Dev/SkeletonCommand.php b/src/StaticPHP/Command/Dev/SkeletonCommand.php
deleted file mode 100644
index b19eb4a1..00000000
--- a/src/StaticPHP/Command/Dev/SkeletonCommand.php
+++ /dev/null
@@ -1,402 +0,0 @@
-output->writeln('The dev:skel command is not available in phar mode.');
- return 1;
- }
- if (SystemTarget::getTargetOS() === 'Windows') {
- $this->output->writeln('The dev:skel command is not available on Windows systems.');
- return 1;
- }
-
- $this->runMainMenu();
-
- return 0;
- }
-
- public function validatePackageName(string $name): ?string
- {
- if (!preg_match('/^[a-zA-Z0-9_-]+$/', $name)) {
- return 'Library name can only contain letters, numbers, underscores, and hyphens.';
- }
- // must start with a letter
- if (!preg_match('/^[a-zA-Z]/', $name)) {
- return 'Library name must start with a letter.';
- }
- return null;
- }
-
- private function runMainMenu(): void
- {
- $main = select('Please select the skeleton option', [
- 'library' => 'Create a new library package',
- 'target' => 'Create a new target package',
- 'php-extension' => 'Create a new PHP extension',
- 'q' => 'Exit',
- ]);
- $generator = match ($main) {
- 'library' => $this->runCreateLib(),
- 'target' => $this->runCreateTarget(),
- 'php-extension' => $this->runCreateExt(),
- 'q' => exit(0),
- default => null,
- };
- $write = $generator->writeAll();
- $this->output->writeln("Package config in: {$write['package_config']}");
- $this->output->writeln("Artifact config in: {$write['artifact_config']}");
- $this->output->writeln('Package class:');
- $this->output->writeln($write['package_class_content']);
- }
-
- private function runCreateLib(): PackageGenerator
- {
- // init empty
- $static_libs = '';
- $headers = '';
- $static_bins = '';
- $pkg_configs = '';
-
- // ask name
- $package_name = text('Please enter your library name', placeholder: 'e.g. pcre2', validate: [$this, 'validatePackageName']);
-
- // ask OS
- $os = select("[{$package_name}] On which OS family do you want to build this library?", [
- 'unix' => 'Both Linux and Darwin (unix-like OS)',
- 'linux' => 'Linux only',
- 'macos' => 'Darwin(macOS) only',
- 'windows' => 'Windows only',
- 'all' => 'All supported OS (' . implode(', ', SUPPORTED_OS_FAMILY) . ')',
- ]);
-
- $produce = select("[{$package_name}] What does this library produce?", [
- 'static_libs' => 'Static Libraries (.a/.lib)',
- 'headers' => 'Header Files (.h)',
- 'static_bins' => 'Static Binaries (executables)',
- 'pkg_configs' => 'Pkg-Config files (.pc)',
- 'all' => 'All of the above',
- ]);
-
- if ($produce === 'all' || $produce === 'static_libs') {
- $static_libs = text(
- 'Please enter the names of the static libraries produced',
- placeholder: 'e.g. libpcre2.a, libbar.a',
- default: str_starts_with($package_name, 'lib') ? "{$package_name}.a" : "lib{$package_name}.a",
- validate: function ($value) {
- $names = array_map('trim', explode(',', $value));
- if (array_any($names, fn ($name) => !preg_match('/^[a-zA-Z0-9_.-]+$/', $name))) {
- return 'Library names can only contain letters, numbers, underscores, hyphens, and dots.';
- }
- return null;
- },
- hint: 'Separate multiple names with commas'
- );
- }
- if ($produce === 'all' || $produce === 'headers') {
- $headers = text(
- 'Please enter the names of the header files produced',
- placeholder: 'e.g. foo.h, bar.h',
- default: str_starts_with($package_name, 'lib') ? str_replace('lib', '', $package_name) . '.h' : $package_name . '.h',
- validate: function ($value) {
- $names = array_map('trim', explode(',', $value));
- if (array_any($names, fn ($name) => !preg_match('/^[a-zA-Z0-9_.-]+$/', $name))) {
- return 'Header file names can only contain letters, numbers, underscores, hyphens, and dots.';
- }
- return null;
- },
- hint: 'Separate multiple names with commas, directories are allowed (e.g. openssl directory)'
- );
- }
- if ($produce === 'all' || $produce === 'static_bins') {
- $static_bins = text(
- 'Please enter the names of the static binaries produced',
- placeholder: 'e.g. foo, bar',
- default: $package_name,
- validate: function ($value) {
- $names = array_map('trim', explode(',', $value));
- if (array_any($names, fn ($name) => !preg_match('/^[a-zA-Z0-9_.-]+$/', $name))) {
- return 'Binary names can only contain letters, numbers, underscores, hyphens, and dots.';
- }
- return null;
- },
- hint: 'Separate multiple names with commas'
- );
- }
- if ($produce === 'all' || $produce === 'pkg_configs') {
- $pkg_configs = text(
- 'Please enter the names of the pkg-config files produced',
- placeholder: 'e.g. foo.pc, bar.pc',
- default: str_starts_with($package_name, 'lib') ? str_replace('lib', '', $package_name) . '.pc' : $package_name . '.pc',
- validate: function ($value) {
- if (!str_ends_with($value, '.pc')) {
- return 'Pkg-config file names must end with .pc extension.';
- }
- return null;
- },
- hint: 'Separate multiple names with commas'
- );
- }
-
- if ($headers === '' && $static_bins === '' && $static_libs === '' && $pkg_configs === '') {
- $this->output->writeln('You must specify at least one of static libraries, header files, or static binaries produced.');
- exit(1);
- }
-
- // ask source
- $artifact_generator = $this->runCreateArtifact($package_name, true, false, null);
- $package_generator = new PackageGenerator($package_name, 'library');
- // set artifact
- $package_generator = $package_generator->addArtifact($artifact_generator);
- // set os
- $package_generator = match ($os) {
- 'unix' => $package_generator->enableBuild(['Darwin', 'Linux'], 'build'),
- 'linux' => $package_generator->enableBuild(['Linux'], 'build'),
- 'macos' => $package_generator->enableBuild(['Darwin'], 'build'),
- 'windows' => $package_generator->enableBuild(['Windows'], 'build'),
- 'all' => $package_generator->enableBuild(SUPPORTED_OS_FAMILY, 'build'),
- default => $package_generator,
- };
- // set produce
- if ($static_libs !== '') {
- $lib_names = array_map('trim', explode(',', $static_libs));
- foreach ($lib_names as $lib_name) {
- $package_generator = $package_generator->addStaticLib($lib_name, $os === 'all' ? 'all' : ($os === 'unix' ? 'unix' : $os));
- }
- }
- if ($headers !== '') {
- $header_names = array_map('trim', explode(',', $headers));
- foreach ($header_names as $header_name) {
- $package_generator = $package_generator->addHeaderFile($header_name, $os === 'all' ? 'all' : ($os === 'unix' ? 'unix' : $os));
- }
- }
- if ($static_bins !== '') {
- $bin_names = array_map('trim', explode(',', $static_bins));
- foreach ($bin_names as $bin_name) {
- $package_generator = $package_generator->addStaticBin($bin_name, $os === 'all' ? 'all' : ($os === 'unix' ? 'unix' : $os));
- }
- }
- if ($pkg_configs !== '') {
- $pc_names = array_map('trim', explode(',', $pkg_configs));
- foreach ($pc_names as $pc_name) {
- $package_generator = $package_generator->addPkgConfigFile($pc_name, $os === 'all' ? 'all' : ($os === 'unix' ? 'unix' : $os));
- }
- }
- // ask for package config writing selection, same as artifact
- $package_configs = Registry::getLoadedPackageConfigs();
- $package_config_file = select("[{$package_name}] Please select the package config file to write the package config to", $package_configs);
- return $package_generator->setConfigFile($package_config_file);
- }
-
- private function runCreateArtifact(
- string $package_name,
- ?bool $create_source,
- ?bool $create_binary,
- string|true|null $default_extract_dir = true
- ): ArtifactGenerator {
- $artifact = new ArtifactGenerator($package_name);
-
- if ($create_source === null) {
- $create_source = confirm("[{$package_name}] Do you want to create a source artifact?");
- }
-
- if (!$create_source) {
- goto binary;
- }
-
- $source_type = select("[{$package_name}] Where is the source code located?", SPC_DOWNLOAD_TYPE_DISPLAY_NAME);
-
- $source_config = $this->askDownloadTypeConfig($package_name, $source_type, $default_extract_dir, 'source');
- $artifact = $artifact->setSource($source_config);
-
- binary:
- if ($create_binary === null) {
- $create_binary = confirm("[{$package_name}] Do you want to create a binary artifact?");
- }
-
- if (!$create_binary) {
- goto end;
- }
-
- $binary_fix = [
- 'macos-x86_64' => null,
- 'macos-aarch64' => null,
- 'linux-x86_64' => null,
- 'linux-aarch64' => null,
- 'windows-x86_64' => null,
- ];
- while (($os = select("[{$package_name}] Please configure the binary downloading options for OS", [
- 'macos-x86_64' => 'macos-x86_64' . ($binary_fix['macos-x86_64'] ? ' (done)' : ''),
- 'macos-aarch64' => 'macos-aarch64' . ($binary_fix['macos-aarch64'] ? ' (done)' : ''),
- 'linux-x86_64' => 'linux-x86_64' . ($binary_fix['linux-x86_64'] ? ' (done)' : ''),
- 'linux-aarch64' => 'linux-aarch64' . ($binary_fix['linux-aarch64'] ? ' (done)' : ''),
- 'windows-x86_64' => 'windows-x86_64' . ($binary_fix['windows-x86_64'] ? ' (done)' : ''),
- 'copy' => 'Duplicate from another OS',
- 'finish' => 'Submit',
- ])) !== 'finish') {
- $source_type = select("[{$package_name}] Where is the binary for {$os} located?", SPC_DOWNLOAD_TYPE_DISPLAY_NAME);
- $source_config = $this->askDownloadTypeConfig($package_name, $source_type, $default_extract_dir, 'binary');
- // set to artifact
- $artifact = $artifact->setBinary($os, $source_config);
- $binary_fix[$os] = true;
- }
-
- end:
-
- // generate config files, select existing package config file to write
- $artifact_configs = Registry::getLoadedArtifactConfigs();
- $artifact_config_file = select("[{$package_name}] Please select the artifact config file to write the artifact config to", $artifact_configs);
- return $artifact->setConfigFile($artifact_config_file);
- }
-
- private function runCreateTarget(): PackageGenerator
- {
- throw new WrongUsageException('Not implemented');
- }
-
- private function runCreateExt(): PackageGenerator
- {
- throw new WrongUsageException('Not implemented');
- }
-
- private function askDownloadTypeConfig(string $package_name, int|string $source_type, bool|string|null $default_extract_dir, string $config_type): array
- {
- $source_config = ['type' => $source_type];
- switch ($source_type) {
- case 'bitbuckettag':
- $source_config['repo'] = text("[{$package_name}] Please enter the BitBucket repository (e.g. user/repo)");
- break;
- case 'filelist':
- $source_config['url'] = text(
- "[{$package_name}] Please enter the file index website URL",
- placeholder: 'e.g. https://ftp.gnu.org/pub/gnu/gettext/',
- hint: 'Make sure the target url is a directory listing page like ftp.gnu.org.'
- );
- $source_config['regex'] = text(
- "[{$package_name}] Please enter the regex pattern to match the archive file",
- placeholder: 'e.g. /gettext-(\d+\.\d+(\.\d+)?)\.tar\.gz/',
- default: "/href=\"(?{$package_name}-(?[^\"]+)\\.tar\\.gz)\"/",
- hint: 'Make sure the regex contains a capturing group for the version number.'
- );
- break;
- case 'git':
- $source_config['url'] = text(
- "[{$package_name}] Please enter the Git repository URL",
- validate: function ($value) {
- if (!filter_var($value, FILTER_VALIDATE_URL) && !preg_match('/^(git|ssh|http|https|git@[-\w.]+):(\/\/)?(.*?)(\.git)(\/?|#[-\d\w._]+?)$/', $value)) {
- return 'Please enter a valid Git repository URL.';
- }
- return null;
- },
- hint: 'e.g. https://github.com/user/repo.git'
- );
- $source_config['rev'] = text(
- "[{$package_name}] Please enter the Git revision (branch, tag, or commit hash)",
- default: 'main',
- hint: 'e.g. main, master, v1.0.0, or a commit hash'
- );
- break;
- case 'ghrel':
- $source_config['repo'] = text("[{$package_name}] Please enter the GitHub repository (e.g. user/repo)");
- $source_config['match'] = text(
- "[{$package_name}] Please enter the regex pattern to match the source archive file",
- placeholder: 'e.g. /foo-(\d+\.\d+(\.\d+)?)\.tar\.gz/',
- default: "{$package_name}-.+\\.tar\\.gz",
- );
- break;
- case 'ghtar':
- case 'ghtagtar':
- $source_config['repo'] = text("[{$package_name}] Please enter the GitHub repository (e.g. user/repo)");
- $source_config['prefer-stable'] = confirm("[{$package_name}] Do you want to prefer stable releases?");
- if ($source_type === 'ghtagtar' && confirm('Do you want to match tags with a specific pattern?', default: false)) {
- $source_config['match'] = text(
- "[{$package_name}] Please enter the regex pattern to match tags",
- placeholder: 'e.g. v(\d+\.\d+(\.\d+)?)',
- );
- }
- break;
- case 'local':
- $source_config['dirname'] = text(
- "[{$package_name}] Please enter the local directory path",
- validate: function ($value) {
- if (trim($value) === '') {
- return 'Local source directory cannot be empty.';
- }
- if (!is_dir($value)) {
- return 'The specified local source directory does not exist.';
- }
- return null;
- },
- );
- break;
- case 'pie':
- $source_config['repo'] = text(
- "[{$package_name}] Please enter the PIE repository name",
- placeholder: 'e.g. user/repo',
- );
- break;
- case 'url':
- $source_config['url'] = text(
- "[{$package_name}] Please enter the file download URL",
- validate: function ($value) {
- if (!filter_var($value, FILTER_VALIDATE_URL)) {
- return 'Please enter a valid URL.';
- }
- return null;
- },
- );
- break;
- case 'custom':
- break;
- }
- // ask extract dir if is true
- if ($default_extract_dir === true) {
- if (confirm('Do you want to specify a custom extract directory?')) {
- $extract_hint = match ($config_type) {
- 'source' => 'the source will be from the `source/` dir by default',
- 'binary' => 'the binary will be from the `pkgroot/{arch}-{os}/` dir by default',
- default => '',
- };
- $default_extract_dir = text(
- "[{$package_name}] Please enter the source extract directory",
- validate: function ($value) {
- if (trim($value) === '') {
- return 'Extract directory cannot be empty.';
- }
- return null;
- },
- hint: 'You can use relative path, ' . $extract_hint . '.'
- );
- } else {
- $default_extract_dir = null;
- }
- }
- if ($default_extract_dir !== null) {
- $source_config['extract'] = $default_extract_dir;
- }
-
- // return config
- return $source_config;
- }
-}
diff --git a/src/StaticPHP/ConsoleApplication.php b/src/StaticPHP/ConsoleApplication.php
index fd7650aa..9e37698c 100644
--- a/src/StaticPHP/ConsoleApplication.php
+++ b/src/StaticPHP/ConsoleApplication.php
@@ -9,7 +9,6 @@ use StaticPHP\Command\BuildTargetCommand;
use StaticPHP\Command\Dev\EnvCommand;
use StaticPHP\Command\Dev\IsInstalledCommand;
use StaticPHP\Command\Dev\ShellCommand;
-use StaticPHP\Command\Dev\SkeletonCommand;
use StaticPHP\Command\Dev\SortConfigCommand;
use StaticPHP\Command\DoctorCommand;
use StaticPHP\Command\DownloadCommand;
@@ -61,7 +60,6 @@ class ConsoleApplication extends Application
new ShellCommand(),
new IsInstalledCommand(),
new EnvCommand(),
- new SkeletonCommand(),
new SortConfigCommand(),
]);
diff --git a/src/StaticPHP/Skeleton/ArtifactGenerator.php b/src/StaticPHP/Skeleton/ArtifactGenerator.php
deleted file mode 100644
index e05f94d1..00000000
--- a/src/StaticPHP/Skeleton/ArtifactGenerator.php
+++ /dev/null
@@ -1,115 +0,0 @@
-name;
- }
-
- public function setSource(array $source): static
- {
- $clone = clone $this;
- $clone->source = $source;
- return $clone;
- }
-
- public function setCustomSource(): static
- {
- $clone = clone $this;
- $clone->source = ['type' => 'custom'];
- $clone->generate_class = true;
- $clone->generate_custom_source_func = true;
- return $clone;
- }
-
- public function getSource(): ?array
- {
- return $this->source;
- }
-
- public function setBinary(string $os, array $config): static
- {
- $clone = clone $this;
- if ($clone->binary === null) {
- $clone->binary = [$os => $config];
- } else {
- $clone->binary[$os] = $config;
- }
- return $clone;
- }
-
- public function generateConfigArray(): array
- {
- $config = [];
-
- if ($this->source) {
- $config['source'] = $this->source;
- }
- if ($this->binary) {
- $config['binary'] = $this->binary;
- }
- return $config;
- }
-
- public function setConfigFile(string $file): static
- {
- $clone = clone $this;
- $clone->config_file = $file;
- return $clone;
- }
-
- /**
- * Write the artifact configuration to the config file.
- */
- public function writeConfigFile(): string
- {
- if ($this->config_file === null) {
- throw new ValidationException('Config file path is not set.');
- }
- $config_array = $this->generateConfigArray();
- $config_file_json = json_decode(FileSystem::readFile($this->config_file), true);
- if (!is_array($config_file_json)) {
- throw new ValidationException('Existing config file is not a valid JSON array.');
- }
-
- $config_file_json[$this->name] = $config_array;
- // sort keys
- ksort($config_file_json);
- $json_content = json_encode($config_file_json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
- if ($json_content === false) {
- throw new ValidationException('Failed to encode config array to JSON.');
- }
- if (file_put_contents($this->config_file, $json_content) === false) {
- throw new FileSystemException("Failed to write config file: {$this->config_file}");
- }
- return $this->config_file;
- }
-}
diff --git a/src/StaticPHP/Skeleton/PackageGenerator.php b/src/StaticPHP/Skeleton/PackageGenerator.php
deleted file mode 100644
index 89802899..00000000
--- a/src/StaticPHP/Skeleton/PackageGenerator.php
+++ /dev/null
@@ -1,412 +0,0 @@
- $depends An array of dependencies required by the package, categorized by operating system. */
- protected array $depends = [];
-
- /** @var array<''|'linux'|'macos'|'unix'|'windows', string[]> $suggests An array of suggested packages for the package, categorized by operating system. */
- protected array $suggests = [];
-
- /** @var array $frameworks An array of macOS frameworks for the package */
- protected array $frameworks = [];
-
- /** @var array<''|'linux'|'macos'|'unix'|'windows', string[]> $static_libs An array of static libraries required by the package, categorized by operating system. */
- protected array $static_libs = [];
-
- /** @var array<''|'linux'|'macos'|'unix'|'windows', string[]> $headers An array of header files required by the package, categorized by operating system. */
- protected array $headers = [];
-
- /** @var array<''|'linux'|'macos'|'unix'|'windows', string[]> $static_bins An array of static binaries required by the package, categorized by operating system. */
- protected array $static_bins = [];
-
- protected ?string $config_file = null;
-
- /** @var null|ArtifactGenerator $artifact Artifact */
- protected ?ArtifactGenerator $artifact = null;
-
- /** @var array $licenses Licenses */
- protected array $licenses = [];
-
- /** @var array<'Darwin'|'Linux'|'Windows', null|string> $build_for_enables Enable build function generating */
- protected array $build_for_enables = [
- 'Darwin' => null,
- 'Linux' => null,
- 'Windows' => null,
- ];
-
- /** @var array */
- protected array $func_executor_binding = [];
-
- /**
- * @param string $package_name Package name
- * @param 'library'|'php-extension'|'target'|'virtual-target' $type Package type ('library', 'target', 'virtual-target', etc.)
- */
- public function __construct(protected string $package_name, protected string $type) {}
-
- /**
- * Add package dependency.
- *
- * @param string $package Package name
- * @param string $os_category Operating system ('' for all OSes, 'unix', 'windows', 'macos')
- */
- public function addDependency(string $package, string $os_category = ''): static
- {
- if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) {
- throw new ValidationException("Invalid OS suffix: {$os_category}");
- }
- $clone = clone $this;
- if (!isset($clone->depends[$os_category])) {
- $clone->depends[$os_category] = [];
- }
- if (!in_array($package, $clone->depends[$os_category], true)) {
- $clone->depends[$os_category][] = $package;
- }
- return $clone;
- }
-
- /**
- * Add package suggestion.
- *
- * @param string $package Package name
- * @param string $os_category Operating system ('' for all OSes)
- */
- public function addSuggestion(string $package, string $os_category = ''): static
- {
- if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) {
- throw new ValidationException("Invalid OS suffix: {$os_category}");
- }
- $clone = clone $this;
- if (!isset($clone->suggests[$os_category])) {
- $clone->suggests[$os_category] = [];
- }
- if (!in_array($package, $clone->suggests[$os_category], true)) {
- $clone->suggests[$os_category][] = $package;
- }
- return $clone;
- }
-
- public function addStaticLib(string $lib_a, string $os_category = ''): static
- {
- if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) {
- throw new ValidationException("Invalid OS suffix: {$os_category}");
- }
- if (!str_ends_with($lib_a, '.lib') && !str_ends_with($lib_a, '.a')) {
- throw new ValidationException("Static library must end with .lib or .a, got: {$lib_a}");
- }
- if (str_ends_with($lib_a, '.lib') && in_array($os_category, ['unix', 'linux', 'macos'], true)) {
- throw new ValidationException("Static library with .lib extension cannot be added for non-Windows OS: {$lib_a}");
- }
- if (str_ends_with($lib_a, '.a') && $os_category === 'windows') {
- throw new ValidationException("Static library with .a extension cannot be added for Windows OS: {$lib_a}");
- }
- if (isset($this->static_libs[$os_category]) && in_array($lib_a, $this->static_libs[$os_category], true)) {
- // already exists
- return $this;
- }
- $clone = clone $this;
- if (!isset($clone->static_libs[$os_category])) {
- $clone->static_libs[$os_category] = [];
- }
- if (!in_array($lib_a, $clone->static_libs[$os_category], true)) {
- $clone->static_libs[$os_category][] = $lib_a;
- }
- return $clone;
- }
-
- public function addHeader(string $header_file, string $os_category = ''): static
- {
- if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) {
- throw new ValidationException("Invalid OS suffix: {$os_category}");
- }
- $clone = clone $this;
- if (!isset($clone->headers[$os_category])) {
- $clone->headers[$os_category] = [];
- }
- if (!in_array($header_file, $clone->headers[$os_category], true)) {
- $clone->headers[$os_category][] = $header_file;
- }
- return $clone;
- }
-
- public function addStaticBin(string $bin_file, string $os_category = ''): static
- {
- if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) {
- throw new ValidationException("Invalid OS suffix: {$os_category}");
- }
- $clone = clone $this;
- if (!isset($clone->static_bins[$os_category])) {
- $clone->static_bins[$os_category] = [];
- }
- if (!in_array($bin_file, $clone->static_bins[$os_category], true)) {
- $clone->static_bins[$os_category][] = $bin_file;
- }
- return $clone;
- }
-
- /**
- * Add package artifact.
- *
- * @param ArtifactGenerator $artifactGenerator Artifact generator
- */
- public function addArtifact(ArtifactGenerator $artifactGenerator): static
- {
- $clone = clone $this;
- $clone->artifact = $artifactGenerator;
- return $clone;
- }
-
- /**
- * Add license from string.
- *
- * @param string $text License content
- */
- public function addLicenseFromString(string $text): static
- {
- $clone = clone $this;
- $clone->licenses[] = [
- 'type' => 'text',
- 'text' => $text,
- ];
- return $clone;
- }
-
- /**
- * Add license from file.
- *
- * @param string $file_path License file path
- */
- public function addLicenseFromFile(string $file_path): static
- {
- $clone = clone $this;
- $clone->licenses[] = [
- 'type' => 'file',
- 'path' => $file_path,
- ];
- return $clone;
- }
-
- /**
- * Enable build for specific OS.
- *
- * @param 'Darwin'|'Linux'|'Windows'|array<'Darwin'|'Linux'|'Windows'> $build_for Build for OS
- */
- public function enableBuild(array|string $build_for, ?string $build_function_name = null): static
- {
- $clone = clone $this;
- if (is_array($build_for)) {
- foreach ($build_for as $bf) {
- $clone = $clone->enableBuild($bf, $build_function_name ?? 'build');
- }
- return $clone;
- }
- if (!in_array($build_for, SUPPORTED_OS_FAMILY, true)) {
- throw new ValidationException("Unsupported build_for value: {$build_for}");
- }
- $clone->build_for_enables[$build_for] = $build_function_name ?? "buildFor{$build_for}";
- return $clone;
- }
-
- /**
- * Bind function executor.
- *
- * @param string $func_name Function name
- * @param ExecutorGenerator $executor Executor generator
- */
- public function addFunctionExecutorBinding(string $func_name, ExecutorGenerator $executor): static
- {
- $clone = clone $this;
- $clone->func_executor_binding[$func_name] = $executor;
- return $clone;
- }
-
- public function generatePackageClassFile(string $namespace, bool $uppercase = false): string
- {
- $printer = new class extends Printer {
- public string $indentation = ' ';
- };
- $file = new PhpFile();
- $namespace = $file->setStrictTypes()->addNamespace($namespace);
-
- $uses = [];
-
- // class name and package attribute
- $class_name = str_replace('-', '_', $uppercase ? ucwords($this->package_name, '-') : $this->package_name);
- $class_attribute = match ($this->type) {
- 'library' => Library::class,
- 'php-extension' => Extension::class,
- 'target', 'virtual-target' => Target::class,
- };
- $package_class = match ($this->type) {
- 'library' => LibraryPackage::class,
- 'php-extension' => PhpExtensionPackage::class,
- 'target', 'virtual-target' => TargetPackage::class,
- };
- $uses[] = $class_attribute;
- $uses[] = $package_class;
- $uses[] = BuildFor::class;
- $uses[] = PackageInstaller::class;
-
- foreach ($uses as $use) {
- $namespace->addUse($use);
- }
-
- // add class attribute
- $class = $namespace->addClass($class_name);
- $class->addAttribute($class_attribute, [$this->package_name]);
-
- // add build functions if enabled
- $funcs = [];
- foreach ($this->build_for_enables as $os_family => $func_name) {
- if ($func_name !== null) {
- $funcs[$func_name][] = $os_family;
- }
- }
- foreach ($funcs as $name => $oss) {
- $method = $class->addMethod(name: $name ?: 'build')
- ->setPublic()
- ->setReturnType('void');
- // check if function executor is bound
- if (isset($this->func_executor_binding[$name])) {
- $executor = $this->func_executor_binding[$name];
- [$executor_use, $code] = $executor->generateCode();
- $namespace->addUse($executor_use);
- $method->setBody($code);
- }
- $method->addParameter('package')->setType($package_class);
- $method->addParameter('installer')->setType(PackageInstaller::class);
- foreach ($oss as $os) {
- $method->addAttribute(BuildFor::class, [$os]);
- }
- }
-
- return $printer->printFile($file);
- }
-
- /**
- * Generate package config
- */
- public function generateConfigArray(): array
- {
- $config = ['type' => $this->type];
-
- // Add dependencies
- foreach ($this->depends as $suffix => $depends) {
- $k = $suffix !== '' ? "depends@{$suffix}" : 'depends';
- $config[$k] = $depends;
- }
-
- // add suggests
- foreach ($this->suggests as $suffix => $suggests) {
- $k = $suffix !== '' ? "suggests@{$suffix}" : 'suggests';
- $config[$k] = $suggests;
- }
-
- // Add frameworks
- if (!empty($this->frameworks)) {
- $config['frameworks'] = $this->frameworks;
- }
-
- // Add static libs
- foreach ($this->static_libs as $suffix => $libs) {
- $k = $suffix !== '' ? "static-libs@{$suffix}" : 'static-libs';
- $config[$k] = $libs;
- }
-
- // Add headers
- foreach ($this->headers as $suffix => $headers) {
- $k = $suffix !== '' ? "headers@{$suffix}" : 'headers';
- $config[$k] = $headers;
- }
-
- // Add static bins
- foreach ($this->static_bins as $suffix => $bins) {
- $k = $suffix !== '' ? "static-bins@{$suffix}" : 'static-bins';
- $config[$k] = $bins;
- }
-
- // Add artifact
- if ($this->artifact !== null) {
- $config['artifact'] = $this->artifact->getName();
- }
-
- // Add licenses
- if (!empty($this->licenses)) {
- if (count($this->licenses) === 1) {
- $config['license'] = $this->licenses[0];
- } else {
- $config['license'] = $this->licenses;
- }
- }
-
- return $config;
- }
-
- public function setConfigFile(string $config_file): static
- {
- $clone = clone $this;
- $clone->config_file = $config_file;
- return $clone;
- }
-
- public function writeConfigFile(): string
- {
- if ($this->config_file === null) {
- throw new ValidationException('Config file path is not set.');
- }
- $config_array = $this->generateConfigArray();
- $config_file_json = json_decode(FileSystem::readFile($this->config_file), true);
- if (!is_array($config_file_json)) {
- throw new ValidationException('Existing config file is not a valid JSON array.');
- }
- $config_file_json[$this->package_name] = $config_array;
- ksort($config_file_json);
- $json_content = json_encode($config_file_json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
- if ($json_content === false) {
- throw new ValidationException('Failed to encode package config to JSON.');
- }
- if (file_put_contents($this->config_file, $json_content) === false) {
- throw new FileSystemException("Failed to write config file: {$this->config_file}");
- }
- return $this->config_file;
- }
-
- public function writeAll(): array
- {
- // write config
- $package_config_file = $this->writeConfigFile();
- $artifact_config_file = $this->artifact->writeConfigFile();
-
- // write class file
- $package_class_file_content = $this->generatePackageClassFile('StaticPHP\Packages');
- $package_class_file_path = str_replace('-', '_', $this->package_name) . '.php';
- // file_put_contents($package_class_file_path, $package_class_file_content); // Uncomment this line to actually write the file
- return [
- 'package_config' => $package_config_file,
- 'artifact_config' => $artifact_config_file,
- 'package_class_file' => $package_class_file_path,
- 'package_class_content' => $package_class_file_content,
- ];
- }
-}