modifs.mineures sans commentaires
This commit is contained in:
		
							parent
							
								
									e9bcf77a4d
								
							
						
					
					
						commit
						4bb386167f
					
				
							
								
								
									
										3
									
								
								.idea/nur-sery.iml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								.idea/nur-sery.iml
									
									
									
										generated
									
									
									
								
							@ -1,6 +1,7 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<module type="WEB_MODULE" version="4">
 | 
			
		||||
  <component name="NewModuleRootManager">
 | 
			
		||||
  <component name="NewModuleRootManager" inherit-compiler-output="true">
 | 
			
		||||
    <exclude-output />
 | 
			
		||||
    <content url="file://$MODULE_DIR$">
 | 
			
		||||
      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="nur\sery\" />
 | 
			
		||||
      <sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="nur\sery\" />
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										67
									
								
								bin/bg-launcher.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										67
									
								
								bin/bg-launcher.php
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,67 @@
 | 
			
		||||
#!/usr/bin/php
 | 
			
		||||
<?php
 | 
			
		||||
require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php';
 | 
			
		||||
 | 
			
		||||
use nur\sery\output\msg;
 | 
			
		||||
use nur\sery\wip\app\app2;
 | 
			
		||||
use nur\sery\wip\app\cli\Application;
 | 
			
		||||
use nur\sery\wip\app\cli\bg_launcher;
 | 
			
		||||
use nur\yaml;
 | 
			
		||||
 | 
			
		||||
class BgLauncherApp extends Application {
 | 
			
		||||
  const PROJDIR = __DIR__.'/../..';
 | 
			
		||||
 | 
			
		||||
  const ACTION_INFOS = 0, ACTION_START = 1, ACTION_STOP = 2;
 | 
			
		||||
  const ARGS = [
 | 
			
		||||
    "purpose" => "lancer un script en tâche de fond",
 | 
			
		||||
    "usage" => "ApplicationClass args...",
 | 
			
		||||
 | 
			
		||||
    ["-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;
 | 
			
		||||
 | 
			
		||||
  function main() {
 | 
			
		||||
    $appClass = $this->args[0] ?? null;
 | 
			
		||||
    if ($appClass === null) {
 | 
			
		||||
      self::die("Vous devez spécifier la classe de l'application");
 | 
			
		||||
    }
 | 
			
		||||
    $appClass = str_replace("/", "\\", $appClass);
 | 
			
		||||
    if (!class_exists($appClass)) {
 | 
			
		||||
      self::die("$appClass: classe non trouvée");
 | 
			
		||||
    }
 | 
			
		||||
    $args = array_slice($this->args, 1);
 | 
			
		||||
 | 
			
		||||
    $useRunfile = constant("$appClass::USE_RUNFILE");
 | 
			
		||||
    if (!$useRunfile) {
 | 
			
		||||
      self::die("Cette application ne supporte le lancement en tâche de fond");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $runfile = app2::with($appClass)->getRunfile();
 | 
			
		||||
    switch ($this->action) {
 | 
			
		||||
    case self::ACTION_START:
 | 
			
		||||
      bg_launcher::_start($args, $runfile);
 | 
			
		||||
      break;
 | 
			
		||||
    case self::ACTION_STOP:
 | 
			
		||||
      bg_launcher::_stop($runfile);
 | 
			
		||||
      break;
 | 
			
		||||
    case self::ACTION_INFOS:
 | 
			
		||||
      yaml::dump($runfile->read());
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$params = app2::params_getenv();
 | 
			
		||||
if ($params !== null) app2::init($params);
 | 
			
		||||
BgLauncherApp::run();
 | 
			
		||||
@ -65,6 +65,7 @@
 | 
			
		||||
	},
 | 
			
		||||
	"bin": [
 | 
			
		||||
		"lib/_launch.php",
 | 
			
		||||
		"bin/bg-launcher.php",
 | 
			
		||||
		"nur_bin/compctl.php",
 | 
			
		||||
		"nur_bin/compdep.php",
 | 
			
		||||
		"nur_bin/cachectl.php",
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,6 @@
 | 
			
		||||
<?php
 | 
			
		||||
require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php';
 | 
			
		||||
 | 
			
		||||
use nur\sery\wip\tools\SteamTrainApp;
 | 
			
		||||
use nur\sery\tools\SteamTrainApp;
 | 
			
		||||
 | 
			
		||||
SteamTrainApp::run();
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,9 @@
 | 
			
		||||
namespace nur\sery\os;
 | 
			
		||||
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
use nur\sery\ExitError;
 | 
			
		||||
use nur\sery\StateException;
 | 
			
		||||
use nur\sery\wip\app\app2;
 | 
			
		||||
 | 
			
		||||
class sh {
 | 
			
		||||
  static final function _quote(string $value): string {
 | 
			
		||||
@ -144,12 +146,12 @@ class sh {
 | 
			
		||||
    $pid = pcntl_fork();
 | 
			
		||||
    if ($pid == -1) {
 | 
			
		||||
      // parent, impossible de forker
 | 
			
		||||
      throw new StateException("unable to fork");
 | 
			
		||||
      throw new ExitError(app2::EC_FORK_PARENT, "unable to fork");
 | 
			
		||||
    } elseif ($pid) {
 | 
			
		||||
      // parent, fork ok
 | 
			
		||||
      pcntl_waitpid($pid, $status);
 | 
			
		||||
      if (pcntl_wifexited($status)) $retcode = pcntl_wexitstatus($status);
 | 
			
		||||
      else $retcode = 127;
 | 
			
		||||
      else $retcode = app2::EC_FORK_CHILD;
 | 
			
		||||
      return $retcode == 0;
 | 
			
		||||
    }
 | 
			
		||||
    // child, fork ok
 | 
			
		||||
 | 
			
		||||
@ -1,27 +1,31 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\tools;
 | 
			
		||||
namespace nur\sery\tools;
 | 
			
		||||
 | 
			
		||||
use nur\sery\output\msg;
 | 
			
		||||
use nur\sery\wip\app\app2;
 | 
			
		||||
use nur\sery\wip\app\cli\Application;
 | 
			
		||||
 | 
			
		||||
class SteamTrainApp extends Application {
 | 
			
		||||
  const PROJDIR = __DIR__.'/../..';
 | 
			
		||||
  const TITLE = "Train à vapeur";
 | 
			
		||||
  const USE_SIGNAL_HANDLER = true;
 | 
			
		||||
  const USE_LOGFILE = true;
 | 
			
		||||
  const USE_RUNFILE = true;
 | 
			
		||||
  const USE_RUNLOCK = true;
 | 
			
		||||
  const USE_SIGNAL_HANDLER = true;
 | 
			
		||||
 | 
			
		||||
  const ARGS = [
 | 
			
		||||
    "purpose" => self::TITLE,
 | 
			
		||||
    "description" => <<<EOT
 | 
			
		||||
Cette application peut être utilisée pour tester le lancement des tâches de fond
 | 
			
		||||
EOT,
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  function main() {
 | 
			
		||||
    $runfile = app2::get()->getRunfile();
 | 
			
		||||
    $runfile->action("Running train...", 100);
 | 
			
		||||
    for ($i = 1; $i <= 100; $i++) {
 | 
			
		||||
    $count = 100;
 | 
			
		||||
    app2::action("Running train...", $count);
 | 
			
		||||
    for ($i = 1; $i <= $count; $i++) {
 | 
			
		||||
      msg::print("Tchou-tchou! x $i");
 | 
			
		||||
      $runfile->step();
 | 
			
		||||
      app2::step();
 | 
			
		||||
      sleep(1);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
							
								
								
									
										25
									
								
								tests/wip/app/argsTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tests/wip/app/argsTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace nur\sery\wip\app;
 | 
			
		||||
 | 
			
		||||
use nulib\tests\TestCase;
 | 
			
		||||
 | 
			
		||||
class argsTest extends TestCase {
 | 
			
		||||
  function testFrom_array() {
 | 
			
		||||
    self::assertSame([], args::from_array(null));
 | 
			
		||||
    self::assertSame([], args::from_array([]));
 | 
			
		||||
    self::assertSame([], args::from_array([false]));
 | 
			
		||||
    self::assertSame(["x"], args::from_array(["x", false]));
 | 
			
		||||
 | 
			
		||||
    self::assertSame(["--opt"], args::from_array(["--opt"]));
 | 
			
		||||
    self::assertSame(["--opt", "value"], args::from_array(["--opt", "value"]));
 | 
			
		||||
 | 
			
		||||
    self::assertSame([], args::from_array(["opt" => false]));
 | 
			
		||||
    self::assertSame(["--opt"], args::from_array(["opt" => true]));
 | 
			
		||||
    self::assertSame(["--opt", "value"], args::from_array(["opt" => "value"]));
 | 
			
		||||
    self::assertSame(["--opt", "42"], args::from_array(["opt" => 42]));
 | 
			
		||||
    self::assertSame(["--opt", "1", "2", "3", "--"], args::from_array(["opt" => [1, 2, 3]]));
 | 
			
		||||
 | 
			
		||||
    self::assertSame(["x", "1", "2", "3", "y"], args::from_array(["x", [1, 2, 3], "y"]));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -269,6 +269,7 @@ class RunFile {
 | 
			
		||||
        "action_current_step" => 0,
 | 
			
		||||
      ];
 | 
			
		||||
    });
 | 
			
		||||
    app2::_dispatch_signals();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** indiquer qu'une étape est franchie dans l'action en cours */
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,6 @@ use nur\sery\cl;
 | 
			
		||||
use nur\sery\ExitError;
 | 
			
		||||
use nur\sery\os\path;
 | 
			
		||||
use nur\sery\os\sh;
 | 
			
		||||
use nur\sery\output\msg;
 | 
			
		||||
use nur\sery\php\func;
 | 
			
		||||
use nur\sery\str;
 | 
			
		||||
use nur\sery\ValueException;
 | 
			
		||||
@ -476,6 +475,10 @@ class app2 {
 | 
			
		||||
 | 
			
		||||
  #############################################################################
 | 
			
		||||
 | 
			
		||||
  const EC_UNDEAD = 247;
 | 
			
		||||
  const EC_REAPABLE = 248;
 | 
			
		||||
  const EC_FORK_CHILD = 249;
 | 
			
		||||
  const EC_FORK_PARENT = 250;
 | 
			
		||||
  const EC_DISABLED = 251;
 | 
			
		||||
  const EC_LOCKED = 252;
 | 
			
		||||
  const EC_BAD_COMMAND = 253;
 | 
			
		||||
@ -536,4 +539,14 @@ class app2 {
 | 
			
		||||
      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);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										39
									
								
								wip/app/args.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								wip/app/args.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\app;
 | 
			
		||||
 | 
			
		||||
use nur\sery\A;
 | 
			
		||||
use nur\sery\str;
 | 
			
		||||
 | 
			
		||||
class args {
 | 
			
		||||
  /**
 | 
			
		||||
   * transformer une liste d'argument de la forme
 | 
			
		||||
   * - ["myArg" => $value]  devient  ["--my-arg", "$value"]
 | 
			
		||||
   * - ["myOpt" => true]    devient  ["--my-opt"]
 | 
			
		||||
   * - ["myOpt" => false]   est omis
 | 
			
		||||
   * - les autres valeurs sont prises telles quelles
 | 
			
		||||
   */
 | 
			
		||||
  static function from_array(?array $array): array {
 | 
			
		||||
    $args = [];
 | 
			
		||||
    if ($array === null) return $args;
 | 
			
		||||
    $index = 0;
 | 
			
		||||
    foreach ($array as $arg => $value) {
 | 
			
		||||
      if ($value === false) continue;
 | 
			
		||||
      if ($arg === $index) {
 | 
			
		||||
        $index++;
 | 
			
		||||
      } else {
 | 
			
		||||
        $arg = str::us2camel($arg);
 | 
			
		||||
        $arg = str::camel2us($arg, false, "-");
 | 
			
		||||
        $arg = str_replace("_", "-", $arg);
 | 
			
		||||
        $args[] = "--$arg";
 | 
			
		||||
        if (is_array($value)) $value[] = "--";
 | 
			
		||||
        elseif ($value === true) $value = null;
 | 
			
		||||
      }
 | 
			
		||||
      if (is_array($value)) {
 | 
			
		||||
        A::merge($args, array_map("strval", $value));
 | 
			
		||||
      } elseif ($value !== null) {
 | 
			
		||||
        $args[] = "$value";
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return $args;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,5 +1,119 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\app\cli;
 | 
			
		||||
 | 
			
		||||
use nur\sery\ExitError;
 | 
			
		||||
use nur\sery\file\TmpfileWriter;
 | 
			
		||||
use nur\sery\os\path;
 | 
			
		||||
use nur\sery\os\proc\Cmd;
 | 
			
		||||
use nur\sery\output\msg;
 | 
			
		||||
use nur\sery\StateException;
 | 
			
		||||
use nur\sery\wip\app\app2;
 | 
			
		||||
use nur\sery\wip\app\args;
 | 
			
		||||
use nur\sery\wip\app\RunFile;
 | 
			
		||||
 | 
			
		||||
class bg_launcher {
 | 
			
		||||
  /**
 | 
			
		||||
   * transformer une liste d'argument de la forme
 | 
			
		||||
   * - ["myArg" => $value]  devient  ["--my-arg", "$value"]
 | 
			
		||||
   * - ["myOpt" => true]    devient  ["--my-opt"]
 | 
			
		||||
   * - ["myOpt" => false]   est momis
 | 
			
		||||
   * - les valeurs séquentielles sont prises telles quelles
 | 
			
		||||
   */
 | 
			
		||||
  static function verifix_args(array $args): array {
 | 
			
		||||
    $args = args::from_array($args);
 | 
			
		||||
    # corriger le chemin de l'application pour qu'il soit absolu et normalisé
 | 
			
		||||
    $args[0] = path::abspath($args[0]);
 | 
			
		||||
    return $args;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function launch(string $appClass, array $args): int {
 | 
			
		||||
    $app = app2::get();
 | 
			
		||||
    $vendorBindir = $app->getVendorbindir();
 | 
			
		||||
    $launch_php = "$vendorBindir/_launch.php";
 | 
			
		||||
    if (!file_exists($launch_php)) {
 | 
			
		||||
      $launch_php = __DIR__."/../../lib/_launch.php";
 | 
			
		||||
    }
 | 
			
		||||
    $tmpfile = new TmpfileWriter();
 | 
			
		||||
    $tmpfile->keep()->serialize($app->getParams());
 | 
			
		||||
 | 
			
		||||
    $args = self::verifix_args($args);
 | 
			
		||||
    $cmd = new Cmd([
 | 
			
		||||
      $launch_php,
 | 
			
		||||
      "--internal-use", $tmpfile->getFile(),
 | 
			
		||||
      $appClass, "--", ...$args,
 | 
			
		||||
    ]);
 | 
			
		||||
    $cmd->addRedir("both", "/tmp/nulib_app_launcher-launch.log");
 | 
			
		||||
    $cmd->passthru($exitcode);
 | 
			
		||||
 | 
			
		||||
    # attendre un peu que la commande aie le temps de s'initialiser
 | 
			
		||||
    sleep(1);
 | 
			
		||||
 | 
			
		||||
    $tmpfile->close();
 | 
			
		||||
    return $exitcode;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function _start(array $args, Runfile $runfile): bool {
 | 
			
		||||
    if ($runfile->warnIfLocked()) return false;
 | 
			
		||||
    $pid = pcntl_fork();
 | 
			
		||||
    if ($pid == -1) {
 | 
			
		||||
      # parent, impossible de forker
 | 
			
		||||
      throw new ExitError(app2::EC_FORK_PARENT, "Unable to fork");
 | 
			
		||||
    } elseif ($pid) {
 | 
			
		||||
      # parent, fork ok
 | 
			
		||||
      return true;
 | 
			
		||||
    } else {
 | 
			
		||||
      ## child, fork ok
 | 
			
		||||
      # Créer un groupe de process, pour pouvoir tuer tous les enfants en même temps
 | 
			
		||||
      $runfile->tm_startPg();
 | 
			
		||||
      $logfile = $runfile->getLogfile() ?? "/tmp/NULIB_APP_app_start.log";
 | 
			
		||||
      $pid = posix_getpid();
 | 
			
		||||
      $exitcode = app2::EC_FORK_CHILD;
 | 
			
		||||
      try {
 | 
			
		||||
        # puis lancer la commande
 | 
			
		||||
        $cmd = new Cmd($args);
 | 
			
		||||
        $cmd->addSource("/g/init.env");
 | 
			
		||||
        $cmd->addRedir("both", $logfile, true);
 | 
			
		||||
        msg::debug("$pid: launching\n".$cmd->getCmd());
 | 
			
		||||
        $cmd->fork_exec($exitcode);
 | 
			
		||||
        msg::debug("$pid: exitcode=$exitcode");
 | 
			
		||||
        return true;
 | 
			
		||||
      } finally {
 | 
			
		||||
        $runfile->wfStopped($exitcode);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function _stop(Runfile $runfile): void {
 | 
			
		||||
    $data = $runfile->read();
 | 
			
		||||
    $pid = $data["pg_pid"];
 | 
			
		||||
    if ($pid === null) {
 | 
			
		||||
      msg::warning("$data[name]: groupe de process inconnu");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    msg::action("kill $pid");
 | 
			
		||||
    if (!posix_kill(-$pid, SIGKILL)) {
 | 
			
		||||
      switch (posix_get_last_error()) {
 | 
			
		||||
      case PCNTL_ESRCH:
 | 
			
		||||
        msg::afailure("process inexistant");
 | 
			
		||||
        break;
 | 
			
		||||
      case PCNTL_EPERM:
 | 
			
		||||
        msg::afailure("process non accessible");
 | 
			
		||||
        break;
 | 
			
		||||
      case PCNTL_EINVAL:
 | 
			
		||||
        msg::afailure("signal invalide");
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    $timeout = 10;
 | 
			
		||||
    while ($runfile->tm_isUndead($pid)) {
 | 
			
		||||
      sleep(1);
 | 
			
		||||
      if (--$timeout == 0) {
 | 
			
		||||
        msg::afailure("impossible d'arrêter la tâche");
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    $runfile->wfStopped(app2::EC_REAPABLE);
 | 
			
		||||
    msg::asuccess();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,137 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\wip\app;
 | 
			
		||||
 | 
			
		||||
use nur\sery\app\Runfile;
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
use nur\sery\file\TmpfileWriter;
 | 
			
		||||
use nur\sery\os\path;
 | 
			
		||||
use nur\sery\os\proc\Cmd;
 | 
			
		||||
use nur\sery\output\msg;
 | 
			
		||||
use nur\sery\StateException;
 | 
			
		||||
use nur\sery\str;
 | 
			
		||||
use nur\sery\wip\app\app2;
 | 
			
		||||
 | 
			
		||||
class launcher {
 | 
			
		||||
  /**
 | 
			
		||||
   * transformer une liste d'argument de la forme
 | 
			
		||||
   * - ["myArg" => $value]  devient  ["--my-arg", "$value"]
 | 
			
		||||
   * - ["myOpt" => true]    devient  ["--my-opt"]
 | 
			
		||||
   * - ["myOpt" => false]   est momis
 | 
			
		||||
   * - les valeurs séquentielles sont prises telles quelles
 | 
			
		||||
   */
 | 
			
		||||
  static function verifix_args(array $args): array {
 | 
			
		||||
    if (!cl::is_list($args)) {
 | 
			
		||||
      $fixedArgs = [];
 | 
			
		||||
      $index = 0;
 | 
			
		||||
      foreach ($args as $arg => $value) {
 | 
			
		||||
        if ($arg === $index) {
 | 
			
		||||
          $index++;
 | 
			
		||||
          $fixedArgs[] = $value;
 | 
			
		||||
          continue;
 | 
			
		||||
        } elseif ($value === false) {
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
        $arg = str::us2camel($arg);
 | 
			
		||||
        $arg = str::camel2us($arg, false, "-");
 | 
			
		||||
        $arg = str_replace("_", "-", $arg);
 | 
			
		||||
        $fixedArgs[] = "--$arg";
 | 
			
		||||
        if ($value !== true) $fixedArgs[] = "$value";
 | 
			
		||||
      }
 | 
			
		||||
      $args = $fixedArgs;
 | 
			
		||||
    }
 | 
			
		||||
    # corriger le chemin de l'application pour qu'il soit absolu et normalisé
 | 
			
		||||
    $args[0] = path::abspath($args[0]);
 | 
			
		||||
    return $args;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function launch(string $appClass, array $args): int {
 | 
			
		||||
    $app = app2::get();
 | 
			
		||||
    $vendorBindir = $app->getVendorbindir();
 | 
			
		||||
    $launch_php = "$vendorBindir/_launch.php";
 | 
			
		||||
    if (!file_exists($launch_php)) {
 | 
			
		||||
      $launch_php = __DIR__."/../../lib/_launch.php";
 | 
			
		||||
    }
 | 
			
		||||
    $tmpfile = new TmpfileWriter();
 | 
			
		||||
    $tmpfile->keep()->serialize($app->getParams());
 | 
			
		||||
 | 
			
		||||
    $args = self::verifix_args($args);
 | 
			
		||||
    $cmd = new Cmd([
 | 
			
		||||
      $launch_php,
 | 
			
		||||
      "--internal-use", $tmpfile->getFile(),
 | 
			
		||||
      $appClass, "--", ...$args,
 | 
			
		||||
    ]);
 | 
			
		||||
    $cmd->addRedir("both", "/tmp/nulib_app_launcher-launch.log");
 | 
			
		||||
    $cmd->passthru($exitcode);
 | 
			
		||||
 | 
			
		||||
    # attendre un peu que la commande aie le temps de s'initialiser
 | 
			
		||||
    sleep(1);
 | 
			
		||||
 | 
			
		||||
    $tmpfile->close();
 | 
			
		||||
    return $exitcode;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function _start(array $args, Runfile $runfile): bool {
 | 
			
		||||
    if ($runfile->warnIfLocked()) return false;
 | 
			
		||||
    $pid = pcntl_fork();
 | 
			
		||||
    if ($pid == -1) {
 | 
			
		||||
      # parent, impossible de forker
 | 
			
		||||
      throw new StateException("unable to fork");
 | 
			
		||||
    } elseif ($pid) {
 | 
			
		||||
      # parent, fork ok
 | 
			
		||||
      return true;
 | 
			
		||||
    } else {
 | 
			
		||||
      ## child, fork ok
 | 
			
		||||
      # Créer un groupe de process, pour pouvoir tuer tous les enfants en même temps
 | 
			
		||||
      $runfile->tm_startPg();
 | 
			
		||||
      $logfile = $runfile->getLogfile() ?? "/tmp/nulib_app_launcher-_start.log";
 | 
			
		||||
      $pid = posix_getpid();
 | 
			
		||||
      $exitcode = -776;
 | 
			
		||||
      try {
 | 
			
		||||
        # puis lancer la commande
 | 
			
		||||
        $cmd = new Cmd($args);
 | 
			
		||||
        $cmd->addSource("/g/init.env");
 | 
			
		||||
        $cmd->addRedir("both", $logfile, true);
 | 
			
		||||
        msg::debug("$pid: launching\n".$cmd->getCmd());
 | 
			
		||||
        $cmd->fork_exec($exitcode);
 | 
			
		||||
        msg::debug("$pid: exitcode=$exitcode");
 | 
			
		||||
        return true;
 | 
			
		||||
      } finally {
 | 
			
		||||
        $runfile->wfStopped($exitcode);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function _stop(Runfile $runfile): void {
 | 
			
		||||
    $data = $runfile->read();
 | 
			
		||||
    $pid = $data["pg_pid"];
 | 
			
		||||
    if ($pid === null) {
 | 
			
		||||
      msg::warning("$data[name]: groupe de process inconnu");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    msg::action("kill $pid");
 | 
			
		||||
    if (!posix_kill(-$pid, SIGKILL)) {
 | 
			
		||||
      switch (posix_get_last_error()) {
 | 
			
		||||
      case PCNTL_ESRCH:
 | 
			
		||||
        msg::afailure("process inexistant");
 | 
			
		||||
        break;
 | 
			
		||||
      case PCNTL_EPERM:
 | 
			
		||||
        msg::afailure("process non accessible");
 | 
			
		||||
        break;
 | 
			
		||||
      case PCNTL_EINVAL:
 | 
			
		||||
        msg::afailure("signal invalide");
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    $timeout = 10;
 | 
			
		||||
    while ($runfile->tm_isUndead($pid)) {
 | 
			
		||||
      sleep(1);
 | 
			
		||||
      if (--$timeout == 0) {
 | 
			
		||||
        msg::afailure("impossible d'arrêter la tâche");
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    $runfile->wfStopped(-778);
 | 
			
		||||
    msg::asuccess();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user