From a0cab24e568f5f80de547127af3157f9ebc9daf0 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Thu, 22 Jan 2026 09:32:22 +0800 Subject: [PATCH] Remove skeleton command --- skeleton-test.php | 28 -- src/StaticPHP/Command/Dev/SkeletonCommand.php | 402 ----------------- src/StaticPHP/ConsoleApplication.php | 2 - src/StaticPHP/Skeleton/ArtifactGenerator.php | 115 ----- src/StaticPHP/Skeleton/PackageGenerator.php | 412 ------------------ 5 files changed, 959 deletions(-) delete mode 100644 skeleton-test.php delete mode 100644 src/StaticPHP/Command/Dev/SkeletonCommand.php delete mode 100644 src/StaticPHP/Skeleton/ArtifactGenerator.php delete mode 100644 src/StaticPHP/Skeleton/PackageGenerator.php 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, - ]; - } -}