Bläddra i källkod

+ p5_ant_url_action_base_path and test ant build using it

BUG: ant output not visible
Piotr Labudda 6 år sedan
förälder
incheckning
03476af31c

+ 29 - 0
SE/schema/ant-url_action/default_db.in7_dziennik_koresp/test-async/build.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project basedir="../../../."
+	name="Test_loop"
+	default="test-loop"
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+	xmlns:xs="http://www.w3.org/2001/XMLSchema">
+	<description>
+		Test loop
+	</description>
+
+	<target name="test-loop" description="URL_TASK Test bash/php loop">
+		<echo>*** DBG ant: test-loop: START ***</echo>
+		<exec executable="/bin/bash" dir="${p5_ant_url_action_base_path}">
+			<arg value="${p5_ant_url_action_base_path}/test.sh"/>
+		</exec>
+		<echo>*** DBG ant: test-loop: END ***</echo>
+	</target>
+
+<!-- BUG: no output from test.sh, only from <echo>
+	<target name="test-loop" description="URL_TASK Test bash/php loop">
+		<echo>*** DBG ant: test-loop: START ***</echo>
+		<exec executable="/bin/bash" dir="${p5_ant_url_action_base_path}">
+			<arg value="test.sh"/>
+		</exec>
+		<echo>*** DBG ant: test-loop: END ***</echo>
+	</target>
+-->
+
+</project>

+ 22 - 0
SE/schema/ant-url_action/default_db.in7_dziennik_koresp/test-async/test.php

@@ -0,0 +1,22 @@
+<?php
+
+
+trigger_error("TEST warning START", E_USER_WARNING);
+
+D("LOOP: START");
+for ($i = 0; $i < 10; $i++) {
+	D("LOOP: {$i}");
+	sleep(1);
+}
+D("LOOP: END.");
+
+
+function D($msg) {
+	echo $msg . "\n";
+
+	error_log(implode("\t", [
+		date('Y-m-d H:i:s'),
+		getmypid(),
+		$msg,
+	]) . "\n", 3, '/tmp/ant-test.php.debug.log');
+}

+ 5 - 0
SE/schema/ant-url_action/default_db.in7_dziennik_koresp/test-async/test.sh

@@ -0,0 +1,5 @@
+#!/bin/bash
+
+echo "START..."
+php ./test.php
+echo "END."

+ 1 - 0
SE/se-lib/Core/AsyncJobs.php

@@ -78,6 +78,7 @@ class Core_AsyncJobs {
 			$php_session_id = session_id();
 		}
 		Core_AsyncJobsFiles::createNewJobFiles($idJob, $jobProps = [
+			'p5_ant_url_action_base_path' => APP_PATH_ROOT . "/schema/ant-url_action/{$path}",
 			'webRootUrl' => $webRootUrl,
 			'outputFunctionUrl' => $outputFunctionUrl,
 			'antFunctionUrl' => $antFunctionUrl,

+ 1 - 1
SE/se-lib/Route/Ant.php

@@ -92,7 +92,7 @@ class Route_Ant extends RouteBase {
 		DBG::log("DBG::getAntUrlActionList START");
 		V::exec("ls -1 {$this->pathUrlActions}/*/*/build.xml", $out, $ret);
 		DBG::log($out, 'array', "DBG::getAntUrlActionList ls -1 */*/build.xml ret({$ret})");
-		if (0) { // tmp use glob to store filemtime($file)
+		if (1) { // tmp use glob to store filemtime($file)
 			$antFileList = glob("{$this->pathUrlActions}/*/*/build.xml", GLOB_NOSORT);
 			DBG::log($antFileList, 'array', "DBG::getAntUrlActionList glob */*/build.xml");
 

+ 317 - 62
SE/se-lib/Route/UrlAction/Ant.php

@@ -4,6 +4,7 @@ Lib::loadClass('RouteBase');
 Lib::loadClass('UI');
 Lib::loadClass('DBG');
 Lib::loadClass('Request');
+Lib::loadClass('Response');
 Lib::loadClass('Crypt');
 Lib::loadClass('Route_Ant');
 
@@ -20,70 +21,264 @@ class Route_UrlAction_Ant extends Route_Ant {// @doc @see Route_Ant
     UI::menu();
     UI::startContainer();
     
-    echo UI::hButtonPost("odśwież", [
-      'class' => "btn btn-link",
-      'form.class' => "pull-right",
-      'title' => "Wczytaj ponownie listę dostępnych funkcji",
-      'data' => [
-        'forceUpdate' => '1',
-      ]
-    ]);
-    UI::tag('h1', [], 'Ant');
-    try {
-      $taskList = $this->getAntUrlActionList();
+		echo UI::h('div', [ 'class' => "pull-right" ], [
+			UI::h('a', [
+				'href' => $this->getLink('listLastJobs'),
+				'class' => "btn btn-link",
+			], "Ostatnio uruchione"),
+			UI::hButtonPost("Odśwież", [
+				'class' => "btn btn-link",
+				// 'form.class' => "pull-right",
+				'title' => "Wczytaj ponownie listę dostępnych funkcji",
+				'data' => [
+					'forceUpdate' => '1',
+				]
+			]),
+		]);
+		echo UI::h('h1', [], 'Druki');
 
-      // $featureID = V::get('featureID', '', $_GET);
-      $primaryKey = V::get('primaryKey', '', $_GET, 'word');
-      $typeName = V::get('typeName', '', $_GET, 'word');
-      if (empty($typeName)) throw new Exception("Missing typeName");
-      if (empty($primaryKey)) throw new Exception("Missing primaryKey");
-      $parsedInfo = Core_AclHelper::parseTypeName($typeName);
-      DBG::log($parsedInfo, '', "Ant parseTypeName({$typeName})");
-      $acl = ACL::getAclByNamespace("{$parsedInfo['url']}/{$parsedInfo['name']}");
-      $pkField = $acl->getPrimaryKeyField();
-
-      UI::startTag('ul');
-      foreach ($taskList as $path => $label) {
-        echo UI::h('li', [], [
-          UI::h('a', [
-            'class' => 'btn btn-md btn-link',
-            'href' => $this->getLink('ant', [
-              'path' => $path,
-              'typeName' => $typeName,
-              'primaryKey' => $primaryKey,
-              'primaryKeyField' => $pkField
-            ])
-          ], "Uruchom '{$label}'")
-        ]);
-        $tmpls = $this->getAntUrlActionTemplates($path);
-        if (!empty($tmpls)) {
-          foreach ($tmpls as $tmpl => $labelTmpl) {
-            echo UI::h('div', [ 'style' => "padding-left: 50px" ], [
-              UI::h('a', [
-                'href' => $this->getLink('ant', [
-                  'path' => $path,
-                  'template' => $tmpl,
-                  'typeName' => $typeName,
-                  'primaryKey' => $primaryKey,
-                  'primaryKeyField' => $pkField
-                ]),
-                // TODO: 'onclick' => 'return p5UI_runWPSAsyncJob(event, this)',
-                'class' => 'btn btn-sm btn-link',
-              ], '<i class="glyphicon glyphicon-arrow-right"></i> ' . $labelTmpl)
-            ]);
-          }
-        }
-      }
-      UI::endTag('ul');
-    } catch (Exception $e) {
-      UI::alert('danger', $e->getMessage());
-      DBG::log($e);
-    }
-    UI::endContainer();
+		UI::tryCatchView([ $this, 'listAntView' ]);
+
+		UI::endContainer();
     UI::dol();
+	}
+	function listAntView() {
+		$taskList = $this->getAntUrlActionList();
+
+		// $featureID = V::get('featureID', '', $_GET);
+		$primaryKey = V::get('primaryKey', '', $_GET, 'word');
+		$typeName = V::get('typeName', '', $_GET, 'word');
+		if (empty($typeName)) throw new Exception("Missing typeName");
+		if (empty($primaryKey)) throw new Exception("Missing primaryKey");
+		$parsedInfo = Core_AclHelper::parseTypeName($typeName);
+		DBG::log($parsedInfo, '', "Ant parseTypeName({$typeName})");
+		$acl = ACL::getAclByNamespace("{$parsedInfo['url']}/{$parsedInfo['name']}");
+		$pkField = $acl->getPrimaryKeyField();
+
+		echo UI::h('p', [ 'class' => "text-muted" ], [
+			"Druki dla rekordu '{$primaryKey}' w tabeli ",
+			UI::h('a', [
+				'href' => Router::getRoute('ViewTableAjax')->getLink('', [ 'namespace' => $acl->getNamespace() ])
+			], $acl->getRawLabel()),
+		]);
+
+		UI::inlineJS( __FILE__ . '.async.js', [ // p5UI_runAntAsyncJob
+			'RUN_ANT_JOB_URL' => $this->getLink('startAntJobAjax'),
+			'RUN_TEST_ANT_JOB_URL' => $this->getLink('startTestAntJobAjax'),
+		]);
+		// echo UI::h('div', [ 'style' => "padding-bottom:8px; border-bottom:1px solid #eee;" ], [
+		// 	UI::h('select', [ 'class' => "form-control" ], array_map(function ($label, $path) {
+		// 		return UI::h('option', [ 'value' => $path ], $label);
+		// 	}, $taskList, array_keys($taskList))),
+		// ]);
+		UI::startTag('ul');
+		foreach ($taskList as $path => $label) {
+			echo UI::h('li', [], [
+				UI::h('a', [
+					'class' => 'btn btn-md btn-link',
+					'href' => $this->getLink('ant', [
+						'path' => $path,
+						'typeName' => $typeName,
+						'primaryKey' => $primaryKey,
+						'primaryKeyField' => $pkField
+					])
+				], "Uruchom '{$label}'")
+			]);
+			$tmpls = $this->getAntUrlActionTemplates($path);
+			if (!empty($tmpls)) {
+				foreach ($tmpls as $tmpl => $labelTmpl) {
+					echo UI::h('div', [ 'style' => "padding-left: 50px" ], [
+						UI::h('a', [
+							'href' => $this->getLink('ant', [
+								'path' => $path,
+								'template' => $tmpl,
+								'typeName' => $typeName,
+								'primaryKey' => $primaryKey,
+								'primaryKeyField' => $pkField
+							]),
+							'class' => 'btn btn-sm btn-link',
+						], '<i class="glyphicon glyphicon-arrow-right"></i> ' . $labelTmpl),
+						" ",
+						UI::h('a', [
+							'href' => $this->getLink('ant', [
+								'path' => $path,
+								'template' => $tmpl,
+								'typeName' => $typeName,
+								'primaryKey' => $primaryKey,
+								'primaryKeyField' => $pkField
+							]),
+							'onclick' => 'return p5UI_runAntAsyncJob(event, this)',
+							'data-namespace' => $acl->getNamespace(),
+							'data-primaryKey' => $primaryKey,
+							'data-ant_path' => $path,
+							'data-ant_template' => $tmpl,
+							'class' => 'btn btn-xs btn-default',
+							'title' => "Uruchom asynchronicznie",
+						], "uruchom"),
+						" ",
+						// UI::h('a', [
+						// 	'href' => $this->getLink('ant', [
+						// 		'path' => $path,
+						// 		'template' => $tmpl,
+						// 		'typeName' => $typeName,
+						// 		'primaryKey' => $primaryKey,
+						// 		'primaryKeyField' => $pkField
+						// 	]),
+						// 	'onclick' => 'return p5UI_runAntAsyncJob(event, this, { TEST: 1 })',
+						// 	'data-namespace' => $acl->getNamespace(),
+						// 	'data-primaryKey' => $primaryKey,
+						// 	'data-ant_path' => $path,
+						// 	'data-ant_template' => $tmpl,
+						// 	'class' => 'btn btn-xs btn-link',
+						// 	'title' => "TEST Uruchom asynchronicznie",
+						// ], "test"),
+					]);
+				}
+			}
+		}
+		UI::endTag('ul');
   }
 
-  public function outputAction() {// index.php?_route=UrlAction_Ant&_task=output & path={$path} & file={$file}";
+	function listLastJobsAction() { UI::layout([ get_called_class(), 'listLastJobsView' ]); }
+	static function listLastJobsView() {
+		echo UI::h('h1', [], "Ostatnio uruchomione zadania");
+
+		$postTask = V::get('postTask', '', $_POST);
+		if ('asyncJobStart' === $postTask) UI::tryCatchView([ get_called_class(), 'asyncJobStartPostTask' ], [ 'args' => $_POST ]);
+
+		UI::table([
+			'disable_lp' => true,
+			'rows' => array_map(function ($item) {
+				return array_merge(
+					[
+						'#' => '',
+						'Nr' => '',
+						'Status' => '',
+					],
+					$item,
+					[
+						'#' => self::jobListItem_Akcje($item),
+						'Nr' => $item['ID'],
+						'Status' => self::jobListItem_Status($item['A_STATUS'], $item),
+					]
+				);
+			}, self::fetchUserLastAsyncJobs()),
+		]);
+		throw new Exception("TODO: list last jobs");
+	}
+	static function fetchUserLastAsyncJobs() {
+		return DB::getPDO()->fetchAll("
+			select j.*
+			from CRM_ASYNC_JOB_LOG j
+			where j.USER = :user
+			order by ID DESC
+		", [
+			':user' => User::getLogin(),
+		]);
+	}
+	static function jobListItem_Akcje($item) {
+		return UI::h('div', [ 'class' => "btn-group" ], [
+			UI::h('button', [
+				// 'type' => "button",
+				'class' => "btn btn-xs btn-default dropdown-toggle",
+				'data-toggle' => "dropdown",
+			], [
+				// UI::h('i', [ 'class' => "glyphicon glyphicon-hamburder" ])
+				'Akcje ',
+				UI::h('span', [ 'class' => "caret" ]),
+			]),
+			UI::h('ul', [ 'class' => "dropdown-menu" ], [
+				UI::h('li', [], [
+					UI::h('a', [
+						'href' => self::link('asyncJobDebug', [ 'id' => $item['ID'] ]),
+					], "Debug Info '{$item['ID']}'"),
+				]),
+				UI::h('li', [], [
+					UI::hButtonPost("Uruchom zadanie '{$item['ID']}'", [
+						'class' => "p5-hover",
+						'style' => "padding:3px 20px",
+						// 'form.class' => "pull-right",
+						// 'title' => "",
+						'data' => [
+							'postTask' => 'asyncJobStart',
+							'id' => $item['ID'],
+						]
+					]),
+				]),
+				// <li role="separator" class="divider"></li>
+			]),
+		]);
+	}
+	static function jobListItem_Status($status, $item) {
+		switch ($status) {
+			case 'WAITING': return UI::h(null, null, [
+				"Oczekujący",
+			]);
+			case 'NORMAL': return UI::h(null, null, [
+				"Uruchomiony",
+			]);
+			case 'OFF_HARD': return UI::h(null, null, [
+				"Zakończony",
+			]);
+			default: return UI::h(null, null, $status);
+		}
+	}
+
+	static function asyncJobStartPostTask($args) {
+		DBG::nicePrint($args, 'DBG: $args');
+		$idJob = V::get('id', 0, $args, 'int');
+		if ($idJob <= 0) throw new Exception("Missing id");
+
+		Lib::loadClass('Core_AsyncJobs');
+		Core_AsyncJobs::startAsyncJob($idJob);
+
+		throw new Exception("TODO: asyncJobStartPostTask");
+	}
+
+	function asyncJobDebugAction() { UI::layout([ $this, 'asyncJobDebugView' ]); }
+	function asyncJobDebugView() {
+		echo UI::h('ul', [ 'class' => "breadcrumb" ], [
+			UI::h('li', [], [
+				UI::h('a', [ 'href' => $this->getLink('listLastJobs') ], "Ostatnio uruchomione zadania"),
+			]),
+			UI::h('li', [ 'class' => "active" ], [
+				"Zadanie - Debug",
+			]),
+		]);
+
+		$idJob = V::get('id', 0, $_GET, 'int');
+		if ($idJob <= 0) throw new Exception("Missing job ID");
+
+		$item = DB::getPDO()->fetchFirst("
+			select j.ID
+		--		, j.ID_FUNCTION
+		--		, j.ID_SOURCE_JOB
+		--		, j.P_ID
+				, j.DATE -- 2020-02-26
+		--		, j.VERSION
+				, j.JOB_NAME -- Ant|default_db/IN7_DZIENNIK_KORESP|default_db.in7_dziennik_koresp/test-async|test-loop
+				, j.LOCK_VALUE -- 66263
+		--		, j.USER
+				, j.A_STATUS
+				, j.A_RECORD_CREATE_DATE
+				, j.A_RECORD_CREATE_AUTHOR
+				, j.A_RECORD_UPDATE_DATE
+				, j.A_RECORD_UPDATE_AUTHOR
+			from CRM_ASYNC_JOB_LOG j
+			where j.USER = :user
+				and j.ID = :id
+		", [
+			':id' => $idJob,
+			':user' => User::getLogin(),
+		]);
+		if (!$item) throw new Exception("Zadanie nie istnieje");
+
+		DBG::nicePrint($item, "Zadanie '{$idJob}'");
+
+		throw new Exception("TODO: asyncJobDebug");
+	}
+
+	public function outputAction() {// index.php?_route=UrlAction_Ant&_task=output & path={$path} & file={$file}";
     $path = V::get('path', '', $_GET);
     if (!$path) throw new Exception("Missing Ant path!");
     $file = V::get('file', '', $_GET);
@@ -93,7 +288,67 @@ class Route_UrlAction_Ant extends Route_Ant {// @doc @see Route_Ant
     throw new Exception("TODO: return output file '$file' from ant task '{$path}'");
   }
 
-  public function antAction() {
+	function startTestAntJobAjaxAction() { Response::sendTryCatchJson([ $this, 'startTestAntJobAjax' ], $args = 'JSON_FROM_REQUEST_BODY'); }
+	function startTestAntJobAjax($args) {
+		sleep(2);
+		$ret = rand(0, 1);
+		switch ($ret) {
+			case 1: return [
+				'type' => "success",
+				'msg' => "Dodano zadanie",
+				'body' => [
+					'id_job' => 123,
+				],
+			];
+			// default: throw new Exception("TODO:startAntJobAjax");
+			default: return [
+				'type' => "error",
+				'msg' => "Wystąpił błąd podczas dodawania zadania",
+			];
+		}
+	}
+
+	function startAntJobAjaxAction() { Response::sendTryCatchJson([ $this, 'startAntJobAjax' ], $args = 'JSON_FROM_REQUEST_BODY'); }
+	function startAntJobAjax($args) {
+		// $args = body: JSON.stringify({
+		// 		namespace: "default_db/IN7_DZIENNIK_KORESP"
+		// 		primaryKey: "66263"
+		// 		ant_path: "default_db.in7_dziennik_koresp/test-bash"
+		// 		ant_template: "test-loop"
+		// })
+
+		$namespace = V::get('namespace', '', $args);
+		$primaryKey = V::get('primaryKey', '', $args);
+		$ant_path = V::get('ant_path', '', $args);
+		$ant_template = V::get('ant_template', '', $args);
+
+		if (empty($namespace)) throw new Exception("Missing namespace");
+		if (empty($primaryKey)) throw new Exception("Missing primaryKey");
+		if (empty($ant_path)) throw new Exception("Missing ant_path");
+		if (empty($ant_template)) throw new Exception("Missing ant_template");
+
+		// TODO: convert antAction to async mode
+		// - register async job or get jobID
+		//   - if exists: show last call info (result, when, etc.) + run again btn
+		//   - if not exists: create new folder with base files, create exec script, run this script in pm2 start
+		//     - parse result into AsyncJob/output and AsyncJob/output_type
+		Lib::loadClass('Core_AsyncJobs');
+		$idJob = Core_AsyncJobs::registerNewAntTask([
+			'namespace' => $namespace,
+			'primaryKey' => $primaryKey,
+			'ant_path' => $ant_path,
+			'ant_template' => $ant_template,
+		]);
+		if (!$idJob) throw new Exception("Wystąpił błąd podczas dodawania zadania");
+
+		return [
+			'type' => "success",
+			'msg' => "Dodano zadanie",
+			'__DBG__args' => $args,
+		];
+	}
+
+	public function antAction() {
     UI::gora();
     UI::startContainer();
     try {
@@ -136,7 +391,7 @@ class Route_UrlAction_Ant extends Route_Ant {// @doc @see Route_Ant
       DBG::log([ 'msg'=>'$webRootUrl', '$webRootUrl'=>$webRootUrl]);
       DBG::log([ 'msg'=>'$outputFunctionUrl', '$outputFunctionUrl'=>$outputFunctionUrl]);
       $testUrl = Request::getPathUri() . "wfs-data.php/default_db/?SERVICE=WFS&VERSION=1.0.0&TYPENAME={$typeName}&SRSNAME=EPSG:3003&featureID={$objectName}.{$primaryKey}";// &REQUEST=GetFeature
-    //  $testUrl = Request::getPathUri() .  "wfs-data.php" ;// &REQUEST=GetFeature
+      //  $testUrl = Request::getPathUri() .  "wfs-data.php" ;// &REQUEST=GetFeature
 
       $cryptedPass = base64_encode(User::getLogin() . ":" . Crypt::decrypt($_SESSION['ADM_PASS_HASH']));
       $uniqID = date("Y-m-d-H_i_s") . substr(md5(time()), 0, 6);// TODO: uniq id for every request