mirror of
https://github.com/deployphp/deployer.git
synced 2025-02-22 16:27:39 +01:00
Better dep init command
This commit is contained in:
parent
f65d013574
commit
10c8b0de8f
@ -4,7 +4,7 @@
|
||||
|
||||
# provision
|
||||
|
||||
[Source](/recipe/provision/provision.php)
|
||||
[Source](/recipe/provision.php)
|
||||
|
||||
|
||||
|
||||
@ -27,19 +27,19 @@
|
||||
|
||||
## Config
|
||||
### php_version
|
||||
[Source](/recipe/provision/provision.php#L8)
|
||||
[Source](/recipe/provision.php#L8)
|
||||
|
||||
|
||||
|
||||
### sudo_password
|
||||
[Source](/recipe/provision/provision.php#L9)
|
||||
[Source](/recipe/provision.php#L9)
|
||||
|
||||
|
||||
|
||||
|
||||
## Tasks
|
||||
### provision
|
||||
[Source](/recipe/provision/provision.php#L14)
|
||||
[Source](/recipe/provision.php#L14)
|
||||
|
||||
|
||||
|
||||
@ -56,57 +56,57 @@ This task is group task which contains next tasks:
|
||||
|
||||
|
||||
### provision:check
|
||||
[Source](/recipe/provision/provision.php#L33)
|
||||
[Source](/recipe/provision.php#L33)
|
||||
|
||||
|
||||
|
||||
### provision:upgrade
|
||||
[Source](/recipe/provision/provision.php#L54)
|
||||
[Source](/recipe/provision.php#L54)
|
||||
|
||||
|
||||
|
||||
### provision:install
|
||||
[Source](/recipe/provision/provision.php#L60)
|
||||
[Source](/recipe/provision.php#L60)
|
||||
|
||||
|
||||
|
||||
### provision:ssh
|
||||
[Source](/recipe/provision/provision.php#L83)
|
||||
[Source](/recipe/provision.php#L83)
|
||||
|
||||
|
||||
|
||||
### provision:user:deployer
|
||||
[Source](/recipe/provision/provision.php#L97)
|
||||
[Source](/recipe/provision.php#L97)
|
||||
|
||||
|
||||
|
||||
### provision:firewall
|
||||
[Source](/recipe/provision/provision.php#L132)
|
||||
[Source](/recipe/provision.php#L132)
|
||||
|
||||
|
||||
|
||||
### provision:install:php
|
||||
[Source](/recipe/provision/provision.php#L140)
|
||||
[Source](/recipe/provision.php#L140)
|
||||
|
||||
|
||||
|
||||
### provision:install:composer
|
||||
[Source](/recipe/provision/provision.php#L165)
|
||||
[Source](/recipe/provision.php#L165)
|
||||
|
||||
|
||||
|
||||
### provision:config:php:sessions
|
||||
[Source](/recipe/provision/provision.php#L198)
|
||||
[Source](/recipe/provision.php#L198)
|
||||
|
||||
|
||||
|
||||
### provision:nginx:dhparam
|
||||
[Source](/recipe/provision/provision.php#L204)
|
||||
[Source](/recipe/provision.php#L204)
|
||||
|
||||
|
||||
|
||||
### provision:nginx
|
||||
[Source](/recipe/provision/provision.php#L215)
|
||||
[Source](/recipe/provision.php#L215)
|
||||
|
||||
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
</rule>
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint">
|
||||
<exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification" />
|
||||
<exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint" />
|
||||
</rule>
|
||||
|
||||
<file>src/Configuration</file>
|
||||
|
@ -18,8 +18,6 @@ require __DIR__ . '/deploy/update_code.php';
|
||||
require __DIR__ . '/deploy/vendors.php';
|
||||
require __DIR__ . '/deploy/writable.php';
|
||||
|
||||
require __DIR__ . '/provision/provision.php';
|
||||
|
||||
use Deployer\Exception\RunException;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\Output;
|
||||
|
@ -17,6 +17,7 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Process\Exception\RuntimeException;
|
||||
use Symfony\Component\Process\Process;
|
||||
use function Deployer\Support\fork;
|
||||
|
||||
class InitCommand extends Command
|
||||
{
|
||||
@ -27,101 +28,186 @@ class InitCommand extends Command
|
||||
$this
|
||||
->setName('init')
|
||||
->setDescription('Initialize deployer in your project')
|
||||
->addOption('template', 't', InputOption::VALUE_OPTIONAL, 'The template of you project')
|
||||
->addOption('filepath', null, InputOption::VALUE_OPTIONAL, 'The file path (default "deploy.php")', 'deploy.php');
|
||||
->addOption('path', 'p', InputOption::VALUE_OPTIONAL, 'Recipe path');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
/** @var FormatterHelper $formatter */
|
||||
$formatter = $this->getHelper('formatter');
|
||||
$initializer = new Initializer();
|
||||
$template = $input->getOption('template');
|
||||
$filepath = $input->getOption('filepath');
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$recipePath = $input->getOption('path');
|
||||
|
||||
if (file_exists($filepath)) {
|
||||
$output->writeln([
|
||||
$formatter->formatBlock(
|
||||
sprintf('The file "%s" already exist.', $filepath),
|
||||
'bg=red;fg=white', true
|
||||
),
|
||||
]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
$project = 'my_project';
|
||||
$repository = '';
|
||||
$hosts = [];
|
||||
$allow = true;
|
||||
|
||||
if ($template === null) {
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
// Welcome message
|
||||
$output->writeln("
|
||||
_____ _
|
||||
| __ \ | |
|
||||
| | | | ___ _ __ | | ___ _ _ ___ _ __
|
||||
| | | |/ _ \ '_ \| |/ _ \| | | |/ _ \ '__|
|
||||
| |__| | __/ |_) | | (_) | |_| | __/ |
|
||||
|_____/ \___| .__/|_|\___/ \__, |\___|_|
|
||||
| | __/ |
|
||||
|_| |___/
|
||||
// Welcome message
|
||||
$output->write("
|
||||
\e[38;2;94;231;223m╔\e[39m\e[38;2;95;230;227m╦\e[39m\e[38;2;96;230;230m╗\e[39m\e[38;2;97;226;230m┌\e[39m\e[38;2;98;221;229m─\e[39m\e[38;2;99;217;228m┐\e[39m\e[38;2;100;213;228m┌\e[39m\e[38;2;101;209;227m─\e[39m\e[38;2;102;205;227m┐\e[39m\e[38;2;103;202;226m┬\e[39m \e[38;2;104;198;226m┌\e[39m\e[38;2;105;194;225m─\e[39m\e[38;2;106;191;225m┐\e[39m\e[38;2;107;187;224m┬\e[39m \e[38;2;108;184;224m┬\e[39m\e[38;2;109;180;223m┌\e[39m\e[38;2;110;177;223m─\e[39m\e[38;2;110;174;222m┐\e[39m\e[38;2;111;171;222m┬\e[39m\e[38;2;112;168;221m─\e[39m\e[38;2;113;165;221m┐\e[39m
|
||||
\e[38;2;114;162;220m║\e[39m\e[38;2;115;159;220m║\e[39m\e[38;2;116;157;219m├\e[39m\e[38;2;117;154;219m┤\e[39m \e[38;2;118;151;218m├\e[39m\e[38;2;119;149;218m─\e[39m\e[38;2;119;147;217m┘\e[39m\e[38;2;120;144;217m│\e[39m \e[38;2;121;142;216m│\e[39m \e[38;2;122;140;216m│\e[39m\e[38;2;123;138;215m└\e[39m\e[38;2;124;136;215m┬\e[39m\e[38;2;125;134;214m┘\e[39m\e[38;2;125;132;214m├\e[39m\e[38;2;126;130;213m┤\e[39m \e[38;2;127;129;213m├\e[39m\e[38;2;129;128;212m┬\e[39m\e[38;2;132;129;212m┘\e[39m
|
||||
\e[38;2;135;130;211m═\e[39m\e[38;2;138;130;211m╩\e[39m\e[38;2;141;131;210m╝\e[39m\e[38;2;144;132;210m└\e[39m\e[38;2;147;133;209m─\e[39m\e[38;2;150;134;209m┘\e[39m\e[38;2;152;134;208m┴\e[39m \e[38;2;155;135;208m┴\e[39m\e[38;2;158;136;207m─\e[39m\e[38;2;160;137;207m┘\e[39m\e[38;2;162;137;206m└\e[39m\e[38;2;165;138;206m─\e[39m\e[38;2;167;139;205m┘\e[39m \e[38;2;169;140;205m┴\e[39m \e[38;2;171;140;204m└\e[39m\e[38;2;173;141;204m─\e[39m\e[38;2;175;142;203m┘\e[39m\e[38;2;177;143;203m┴\e[39m\e[38;2;178;143;202m└\e[39m\e[38;2;180;144;202m─\e[39m
|
||||
|
||||
\e[38;2;94;231;223m█\e[39m\e[38;2;95;230;227m█\e[39m\e[38;2;97;228;230m█\e[39m\e[38;2;98;222;229m█\e[39m\e[38;2;99;217;228m█\e[39m\e[38;2;100;212;228m█\e[39m\e[38;2;102;207;227m█\e[39m\e[38;2;103;202;227m█\e[39m\e[38;2;104;197;226m█\e[39m\e[38;2;105;193;225m█\e[39m\e[38;2;106;188;225m█\e[39m\e[38;2;108;184;224m█\e[39m\e[38;2;109;180;223m█\e[39m\e[38;2;110;176;223m█\e[39m\e[38;2;111;172;222m█\e[39m\e[38;2;112;168;222m█\e[39m\e[38;2;113;164;221m█\e[39m\e[38;2;115;161;220m█\e[39m\e[38;2;116;157;220m█\e[39m\e[38;2;117;154;219m█\e[39m\e[38;2;118;151;218m█\e[39m\e[38;2;119;148;218m█\e[39m\e[38;2;120;145;217m█\e[39m\e[38;2;121;142;216m█\e[39m\e[38;2;122;139;216m█\e[39m\e[38;2;123;137;215m█\e[39m\e[38;2;124;134;215m█\e[39m\e[38;2;126;132;214m█\e[39m\e[38;2;127;130;213m█\e[39m\e[38;2;128;128;213m█\e[39m\e[38;2;132;129;212m█\e[39m\e[38;2;136;130;211m█\e[39m\e[38;2;139;131;211m█\e[39m\e[38;2;143;132;210m█\e[39m\e[38;2;147;133;210m█\e[39m\e[38;2;150;134;209m█\e[39m\e[38;2;153;135;208m█\e[39m\e[38;2;157;136;208m█\e[39m\e[38;2;160;137;207m█\e[39m\e[38;2;163;138;206m█\e[39m\e[38;2;166;138;206m█\e[39m\e[38;2;168;139;205m█\e[39m\e[38;2;171;140;205m█\e[39m\e[38;2;173;141;204m█\e[39m\e[38;2;176;142;203m█\e[39m\e[38;2;178;143;203m█\e[39m\e[38;2;180;144;202m█\e[39m
|
||||
");
|
||||
|
||||
$io->text([
|
||||
'Welcome to the Deployer config generator.',
|
||||
'This utility will walk you through creating a deploy.php file.',
|
||||
'',
|
||||
'Press ^C at any time to quit.',
|
||||
]);
|
||||
$io->text([
|
||||
'Welcome to the <fg=cyan>Deployer</fg=cyan> config generator.',
|
||||
'',
|
||||
'Press ^C at any time to quit.',
|
||||
]);
|
||||
|
||||
// Yes?
|
||||
$io->confirm('Continue?');
|
||||
// Yes?
|
||||
$language = $io->choice('Select recipe language', ['php', 'yaml'], 'php');
|
||||
if (empty($recipePath)) {
|
||||
$recipePath = "deploy.$language";
|
||||
}
|
||||
|
||||
// Template
|
||||
$recipes = $initializer->getRecipes();
|
||||
$template = $io->choice('Select project template', $recipes, 'common');
|
||||
// Template
|
||||
$template = $io->choice('Select project template', $this->recipes(), 'common');
|
||||
|
||||
// Repo
|
||||
$default = false;
|
||||
try {
|
||||
$process = Process::fromShellCommandline('git remote get-url origin');
|
||||
$default = $process->mustRun()->getOutput();
|
||||
$default = trim($default);
|
||||
} catch (RuntimeException $e) {
|
||||
}
|
||||
$repository = $io->ask('Repository', $default);
|
||||
// Repo
|
||||
$default = false;
|
||||
try {
|
||||
$process = Process::fromShellCommandline('git remote get-url origin');
|
||||
$default = $process->mustRun()->getOutput();
|
||||
$default = trim($default);
|
||||
} catch (RuntimeException $e) {
|
||||
}
|
||||
$repository = $io->ask('Repository', $default);
|
||||
|
||||
// Project
|
||||
$default = false;
|
||||
try {
|
||||
$process = Process::fromShellCommandline('basename "$PWD"');
|
||||
$default = $process->mustRun()->getOutput();
|
||||
$default = trim($default);
|
||||
} catch (RuntimeException $e) {
|
||||
}
|
||||
$project = $io->ask('Project name', $default);
|
||||
|
||||
// Hosts
|
||||
$host = null;
|
||||
if (preg_match('/github.com:(?<org>[A-Za-z0-9_\.\-]+)\//', $repository, $m)) {
|
||||
// Guess host
|
||||
if (preg_match('/github.com:(?<org>[A-Za-z0-9_.\-]+)\//', $repository, $m)) {
|
||||
$org = $m['org'];
|
||||
$tempHostFile = tempnam(sys_get_temp_dir(), 'temp-host-file');
|
||||
fork(function () use ($org, $tempHostFile) {
|
||||
try {
|
||||
['blog' => $blog] = Httpie::get('https://api.github.com/orgs/' . $m['org'])->getJson();
|
||||
['blog' => $blog] = Httpie::get('https://api.github.com/orgs/' . $org)->getJson();
|
||||
$host = parse_url($blog, PHP_URL_HOST);
|
||||
file_put_contents($tempHostFile, $host);
|
||||
} catch (\Throwable $e) {
|
||||
// ¯\_(ツ)_/¯
|
||||
}
|
||||
}
|
||||
$hosts = explode(',', $io->ask('Hosts (comma separated)', $host));
|
||||
});
|
||||
}
|
||||
|
||||
file_put_contents($filepath, $initializer->getTemplate($template, $project, $repository, $hosts, $allow));
|
||||
// Project
|
||||
$default = false;
|
||||
try {
|
||||
$process = Process::fromShellCommandline('basename "$PWD"');
|
||||
$default = $process->mustRun()->getOutput();
|
||||
$default = trim($default);
|
||||
} catch (RuntimeException $e) {
|
||||
}
|
||||
$project = $io->ask('Project name', $default);
|
||||
|
||||
// Hosts
|
||||
$host = null;
|
||||
if (isset($tempHostFile)) {
|
||||
$host = file_get_contents($tempHostFile);
|
||||
}
|
||||
$hosts = explode(',', $io->ask('Hosts (comma separated)', $host));
|
||||
|
||||
file_put_contents($recipePath, $this->$language($template, $project, $repository, $hosts));
|
||||
|
||||
$this->telemetry();
|
||||
$output->writeln(sprintf(
|
||||
'<info>Successfully created</info> <comment>%s</comment>',
|
||||
$filepath
|
||||
$recipePath
|
||||
));
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function php(string $template, string $project, string $repository, array $hosts): string
|
||||
{
|
||||
$h = "";
|
||||
foreach ($hosts as $host) {
|
||||
$h .= "host('{$host}');\n";
|
||||
}
|
||||
|
||||
return <<<PHP
|
||||
<?php
|
||||
namespace Deployer;
|
||||
|
||||
require 'recipe/$template.php';
|
||||
require 'recipe/provision.php';
|
||||
|
||||
// Config
|
||||
|
||||
set('application', '{$project}');
|
||||
set('deploy_path', '~/{{application}}');
|
||||
set('repository', '{$repository}');
|
||||
|
||||
add('shared_files', []);
|
||||
add('shared_dirs', []);
|
||||
add('writable_dirs', []);
|
||||
|
||||
// Hosts
|
||||
|
||||
{$h}
|
||||
// Tasks
|
||||
|
||||
task('build', function () {
|
||||
cd('{{release_path}}');
|
||||
run('npm run build');
|
||||
});
|
||||
|
||||
after('deploy:failed', 'deploy:unlock');
|
||||
|
||||
PHP;
|
||||
}
|
||||
|
||||
private function yaml(string $template, string $project, string $repository, array $hosts): string
|
||||
{
|
||||
$h = "";
|
||||
foreach ($hosts as $host) {
|
||||
$h .= " $host:\n deploy_path: '~/{{application}}'\n";
|
||||
}
|
||||
|
||||
return <<<YAML
|
||||
import:
|
||||
- recipe/$template.php
|
||||
- recipe/provision.php
|
||||
|
||||
config:
|
||||
application: '$project'
|
||||
repository: '$repository'
|
||||
shared_files:
|
||||
- .env
|
||||
shared_dirs:
|
||||
- uploads
|
||||
writable_dirs:
|
||||
- uploads
|
||||
|
||||
hosts:
|
||||
{$h}
|
||||
tasks:
|
||||
build:
|
||||
script:
|
||||
- 'cd {{release_path}} && npm run build'
|
||||
|
||||
after:
|
||||
deploy:failed: deploy:unlock
|
||||
|
||||
YAML;
|
||||
}
|
||||
|
||||
private function recipes(): array
|
||||
{
|
||||
$recipes = [];
|
||||
$dir = new \DirectoryIterator(__DIR__ . '/../../recipe');
|
||||
foreach ($dir as $fileinfo) {
|
||||
if ($fileinfo->isDot()) {
|
||||
continue;
|
||||
}
|
||||
if ($fileinfo->isDir()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$recipe = pathinfo($fileinfo->getFilename(), PATHINFO_FILENAME);
|
||||
|
||||
if ($recipe === 'README') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$recipes[] = $recipe;
|
||||
}
|
||||
|
||||
sort($recipes);
|
||||
return $recipes;
|
||||
}
|
||||
}
|
||||
|
@ -1,82 +0,0 @@
|
||||
<?php
|
||||
/* (c) Anton Medvedev <anton@medv.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Deployer\Component\Initializer;
|
||||
|
||||
use function Deployer\cd;
|
||||
use function Deployer\run;
|
||||
use function Deployer\task;
|
||||
|
||||
class Initializer
|
||||
{
|
||||
public function getRecipes()
|
||||
{
|
||||
$recipes = [];
|
||||
$dir = new \DirectoryIterator(__DIR__ . '/../../../recipe');
|
||||
foreach ($dir as $fileinfo) {
|
||||
if ($fileinfo->isDot()) {
|
||||
continue;
|
||||
}
|
||||
if ($fileinfo->isDir()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$recipe = pathinfo($fileinfo->getFilename(), PATHINFO_FILENAME);
|
||||
|
||||
if ($recipe === 'README') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$recipes[] = $recipe;
|
||||
}
|
||||
|
||||
sort($recipes);
|
||||
return $recipes;
|
||||
}
|
||||
|
||||
public function getTemplate(string $template, string $project, string $repository, array $hosts, bool $allow): string
|
||||
{
|
||||
$h = "";
|
||||
foreach ($hosts as $host) {
|
||||
$h .= "host('{$host}');\n";
|
||||
}
|
||||
|
||||
$dontTrack = $allow ? '' : "define('DONT_TRACK', 'ಠ_ಠ');\n";
|
||||
|
||||
return <<<PHP
|
||||
<?php
|
||||
namespace Deployer;
|
||||
{$dontTrack}
|
||||
require 'recipe/$template.php';
|
||||
|
||||
// Config
|
||||
|
||||
set('application', '{$project}');
|
||||
set('deploy_path', '~/{{application}}');
|
||||
set('repository', '{$repository}');
|
||||
|
||||
add('shared_files', []);
|
||||
add('shared_dirs', []);
|
||||
add('writable_dirs', []);
|
||||
|
||||
// Hosts
|
||||
|
||||
{$h}
|
||||
|
||||
// Tasks
|
||||
|
||||
task('deploy:build', function () {
|
||||
cd('{{release_path}}');
|
||||
run('npm run build');
|
||||
});
|
||||
|
||||
//after('deploy:update_code', 'deploy:build');
|
||||
after('deploy:failed', 'deploy:unlock');
|
||||
|
||||
PHP;
|
||||
}
|
||||
}
|
@ -147,7 +147,6 @@ class Configuration implements \ArrayAccess
|
||||
/**
|
||||
* @param mixed $offset
|
||||
* @return bool
|
||||
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
|
@ -64,24 +64,16 @@ function array_merge_alternate(array $original, array $override)
|
||||
|
||||
/**
|
||||
* Determines if the given string contains the given value.
|
||||
*
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
* @return bool
|
||||
*/
|
||||
function str_contains(string $haystack, string $needle)
|
||||
function str_contains(string $haystack, string $needle): bool
|
||||
{
|
||||
return strpos($haystack, $needle) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if string stars with given prefix.
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $startString
|
||||
* @return bool
|
||||
*/
|
||||
function starts_with(string $string, string $startString)
|
||||
function starts_with(string $string, string $startString): bool
|
||||
{
|
||||
$len = strlen($startString);
|
||||
return (substr($string, 0, $len) === $startString);
|
||||
@ -103,23 +95,17 @@ function env_stringify(array $array): string
|
||||
|
||||
/**
|
||||
* Check if var is closure.
|
||||
*
|
||||
* @param $var
|
||||
* @return bool
|
||||
* @param mixed $var
|
||||
*/
|
||||
function is_closure($var)
|
||||
function is_closure($var): bool
|
||||
{
|
||||
return is_object($var) && ($var instanceof \Closure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if all elements satisfy predicate.
|
||||
*
|
||||
* @param array $array
|
||||
* @param \Closure $predicate
|
||||
* @return bool
|
||||
*/
|
||||
function array_all(array $array, $predicate)
|
||||
function array_all(array $array, $predicate): bool
|
||||
{
|
||||
foreach ($array as $key => $value) {
|
||||
if (!$predicate($value, $key)) {
|
||||
@ -131,21 +117,14 @@ function array_all(array $array, $predicate)
|
||||
|
||||
/**
|
||||
* Cleanup CRLF new line endings.
|
||||
* Issue #2111
|
||||
*
|
||||
* @param $string
|
||||
* @return string
|
||||
*/
|
||||
function normalize_line_endings($string)
|
||||
function normalize_line_endings(string $string): string
|
||||
{
|
||||
return str_replace(["\r\n", "\r"], "\n", $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand leading tilde (~) symbol in given path.
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function parse_home_dir(string $path): string
|
||||
{
|
||||
@ -163,3 +142,22 @@ function parse_home_dir(string $path): string
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
function fork(callable $callable)
|
||||
{
|
||||
$pid = null;
|
||||
// Make sure function is not disabled via php.ini "disable_functions"
|
||||
if (extension_loaded('pcntl') && function_exists('pcntl_fork')) {
|
||||
declare(ticks = 1);
|
||||
$pid = pcntl_fork();
|
||||
}
|
||||
if (is_null($pid) || $pid === -1) {
|
||||
// Fork fails or there is no `pcntl` extension.
|
||||
$callable();
|
||||
} elseif ($pid === 0) {
|
||||
// Child process.
|
||||
posix_setsid();
|
||||
$callable();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user