From e75dbb0652fe3e9d980b013f037b982bc8f386e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Hivert?= Date: Thu, 27 Sep 2018 13:48:54 +0200 Subject: [PATCH] Version 1.1 --- README.md | 7 +- configurations/.gitignore | 1 + .../config.json.example | 3 +- dcim.php.example | 24 +- dcim/abstract.php | 6 +- dcim/api/abstract.php | 28 +- dcim/api/location.php | 73 +++- dcim/main.php | 2 +- .../CW - TOOLS-CLI - Location - Root.xml | 67 ++++ .../CW - TOOLS-CLI - Location - Root.xml | 21 ++ services/abstract.php | 353 ++++++++++-------- services/browser.php | 151 ++++++++ services/dcim.php | 54 +-- services/shell/abstract.php | 223 +++++------ services/shell/browser.php | 66 ++++ services/shell/dcim.php | 88 ++--- 16 files changed, 772 insertions(+), 395 deletions(-) create mode 100644 configurations/.gitignore rename config.json.example => configurations/config.json.example (79%) create mode 100644 ressources/dcim/reports/CW - TOOLS-CLI - Location - Root.xml create mode 100644 ressources/dcim/searches/CW - TOOLS-CLI - Location - Root.xml create mode 100644 services/browser.php create mode 100644 services/shell/browser.php diff --git a/README.md b/README.md index 567248d..685407a 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,8 @@ You have to use base PHP-CLI SHELL project that is here: https://github.com/clou * Import profiles which are in ressources/dcim * formats: ressources/dcim/formats * Reports: ressources/dcim/reports - * Searches: ressources/dcim/searches + * Searches: ressources/dcim/searches +__*/!\ Version 1.1 add new profiles!*__ # INSTALLATION @@ -24,9 +25,9 @@ __Do not forget to install php7.1-soap__ #### REPOSITORIES * git clone https://github.com/cloudwatt/php-cli-shell_base -* git checkout tags/v1.0 +* git checkout tags/v1.1 * git clone https://github.com/cloudwatt/php-cli-shell_patchmanager -* git checkout tags/v1.0 +* git checkout tags/v1.1 * Merge these two repositories #### CONFIGURATION FILE diff --git a/configurations/.gitignore b/configurations/.gitignore new file mode 100644 index 0000000..fa7cf6a --- /dev/null +++ b/configurations/.gitignore @@ -0,0 +1 @@ +*.user.json diff --git a/config.json.example b/configurations/config.json.example similarity index 79% rename from config.json.example rename to configurations/config.json.example index 6bda055..820e1cb 100644 --- a/config.json.example +++ b/configurations/config.json.example @@ -1,7 +1,8 @@ { "DEFAULT": { "sys": { - "browserCmd": "xdg-open" + "browserCmd": "xdg-open", + "secureShellCmd": "ssh" } }, diff --git a/dcim.php.example b/dcim.php.example index b121110..aacf375 100644 --- a/dcim.php.example +++ b/dcim.php.example @@ -1,11 +1,29 @@ Saut de ligne avant un texte et non après! + */ + echo "\033[1A"; /** * Change [DCIM_SERVER_KEY] with the key of your PatchManager server in configuration file * Example: $MAIN = new Service_Dcim(__DIR__ . '/config.json', 'myPmKey'); */ - $MAIN = new Service_Dcim(__DIR__ . '/config.json', '[DCIM_SERVER_KEY]'); + $MAIN = new Service_Dcim($configurations, '[DCIM_SERVER_KEY]'); - echo "\r\n"; + echo PHP_EOL; exit(); \ No newline at end of file diff --git a/dcim/abstract.php b/dcim/abstract.php index 8ba3562..3ebe28c 100644 --- a/dcim/abstract.php +++ b/dcim/abstract.php @@ -1,7 +1,7 @@ objectExists(); } elseif($objectId !== null) { - throw new Exception("This object ID '".$objectId."' is not valid", E_USER_ERROR); + throw new Exception("This object ID must be an integer, '".gettype($objectId)."' is not valid", E_USER_ERROR); } } @@ -101,6 +101,32 @@ public function getUserAttr($category, $attrLabel) } } + protected function _getSubObjects($objects, $fieldName, $name) + { + if($objects !== false) + { + if($name !== null) + { + $subObjects = array(); + + foreach($objects as $object) + { + if($object[$fieldName] === $name) { + $subObjects[] = $object; + } + } + + return $subObjects; + } + else { + return $objects; + } + } + else { + return false; + } + } + public function __get($name) { switch(mb_strtolower($name)) diff --git a/dcim/api/location.php b/dcim/api/location.php index c515499..437fa04 100644 --- a/dcim/api/location.php +++ b/dcim/api/location.php @@ -3,14 +3,14 @@ class Dcim_Api_Location extends Dcim_Api_Abstract { const OBJECT_TYPE = 'location'; const REPORT_NAMES = array( + 'root' => 'CW - TOOLS-CLI - Location - Root', 'label' => 'CW - TOOLS-CLI - Location1', 'location' => 'CW - TOOLS-CLI - Location2', 'subLocation' => 'CW - TOOLS-CLI - Location3', ); - const ROOT_SITE = 'Cloudwatt'; - static protected $_rootLocationId = null; + static protected $_rootLocationIds = null; protected $_parentLocationId; protected $_parentLocationApi; @@ -47,21 +47,30 @@ public function getParentLocationId() { if($this->_parentLocationId === null) { + $this->_parentLocationId = false; + $path = $this->getPath(); $path = explode(',', $path); - $locationId = $this->getRootLocationId(); + $selfClassName = static::class; + $Dcim_Api_Location = new $selfClassName(); + $locationId = $Dcim_Api_Location->getSubLocationId($path[0]); - for($i=1; $i_DCIM->getLocationIdByParentLocationIdLocationLabel($locationId, $path[$i], false); + for($i=1; $i_DCIM->getLocationIdByParentLocationIdLocationLabel($locationId, $path[$i], false); - if($locationId === false) { - break; + if($locationId === false) { + break; + } } - } - $this->_parentLocationId = ($i === count($path)) ? ($locationId) : (false); + if($i === count($path)) { + $this->_parentLocationId = $locationId; + } + } } return $this->_parentLocationId; @@ -105,7 +114,7 @@ public function getSubLocationIds() return $this->_DCIM->getSubLocationIds($this->getLocationId(), false); } else { - return false; + return $this->getRootLocationIds(); } } @@ -115,7 +124,9 @@ public function getSubLocationId($locationLabel) return $this->_DCIM->getLocationIdByParentLocationIdLocationLabel($this->getLocationId(), $locationLabel, false); } else { - return false; + $results = self::$_DCIM->getReportResults(self::REPORT_NAMES['root']); + $result = $this->_getSubObjects($results, 'name', $locationLabel); + return (Tools::is('array', $result) && count($result) === 1) ? ($result[0]['entity_id']) : (false); } } @@ -155,10 +166,9 @@ public function __call($method, $parameters = null) { switch($method) { - /*case 'getRootLocationId': - return self::getRootLocationId();*/ - default: + default: { throw new Exception('Method '.$method.' does not exist', E_USER_ERROR); + } } } @@ -177,14 +187,43 @@ public function __get($name) public static function getRootLocationId() { - if(self::$_rootLocationId === null) { - $result = self::$_DCIM->getSiteId(self::ROOT_SITE); - self::$_rootLocationId = (self::$_DCIM->isValidReturn($result)) ? ($result) : (false); + if(self::$_rootLocationId === null) + { + $results = self::$_DCIM->getReportResults(self::REPORT_NAMES['root']); + + if(Tools::is('array', $results) && count($results) === 1) { + self::$_rootLocationId = $results[0]['entity_id']; + } + else { + throw new Exception("Unable to get root location ID", E_USER_ERROR); + } } return self::$_rootLocationId; } + public static function getRootLocationIds() + { + if(self::$_rootLocationIds === null) + { + $results = self::$_DCIM->getReportResults(self::REPORT_NAMES['root']); + + if(Tools::is('array&&count>0', $results)) + { + array_walk($results, function(&$item) { + $item = $item['entity_id']; + }); + + self::$_rootLocationIds = $results; + } + else { + throw new Exception("Unable to retreive root location IDs", E_USER_ERROR); + } + } + + return self::$_rootLocationIds; + } + public static function searchLocations($locationLabel, $locationId = null, $recursion = false) { $args = array('label' => $locationLabel); diff --git a/dcim/main.php b/dcim/main.php index 6e2a5c8..3052334 100644 --- a/dcim/main.php +++ b/dcim/main.php @@ -1,5 +1,5 @@ + + CW - TOOLS-CLI - Location - Root + INFTSK-5007 + + + + CW - TOOLS-CLI - Location - Root + 0&1 + + + location.parent.name + STRING + HAS_VALUE + + + + + location.parent.layer + STRING + HAS_VALUE + + + + + + + CW - TOOLS-CLI - Location + INFTSK-5007 + + + location.entityId + + + location.name + + + location.parent + com.patchmanager.shared.beans.dataformat.renderer.ExpressionRenderer + + {qname} + + + + + + location.template + com.patchmanager.shared.beans.dataformat.renderer.ExpressionRenderer + + {name} + + + + location.parent + com.patchmanager.shared.beans.dataformat.renderer.ExpressionRenderer + + {qname} + + + + location.name + + + + + + diff --git a/ressources/dcim/searches/CW - TOOLS-CLI - Location - Root.xml b/ressources/dcim/searches/CW - TOOLS-CLI - Location - Root.xml new file mode 100644 index 0000000..3ff3f39 --- /dev/null +++ b/ressources/dcim/searches/CW - TOOLS-CLI - Location - Root.xml @@ -0,0 +1,21 @@ + + + CW - TOOLS-CLI - Location - Root + 0&1 + + + location.parent.name + STRING + HAS_VALUE + + + + + location.parent.layer + STRING + HAS_VALUE + + + + + diff --git a/services/abstract.php b/services/abstract.php index 2cad978..f17e7f5 100644 --- a/services/abstract.php +++ b/services/abstract.php @@ -1,12 +1,14 @@ _debug = (bool) $debug; } - $this->_CONFIG = CONFIG::getInstance($configFilename); + $this->_CONFIG = CONFIG::getInstance(); + $this->_CONFIG->loadConfigurations($configFilename, false); $this->_SHELL = new SHELL($this->_commands, $this->_inlineArgCmds, $this->_outlineArgCmds, $this->_manCommands); $this->_SHELL->debug($this->_debug)->setHistoryFilename(static::SHELL_HISTORY_FILENAME); @@ -82,7 +93,11 @@ public function test($cmd, array $args = array()) protected function _init() { $this->_oneShotCall(); + + $this->_preLauchingShell(); $this->_launchShell(); + $this->_postLauchingShell(); + return $this; } @@ -99,32 +114,26 @@ protected function _oneShotCall() { if($this->isOneShotCall()) { - $cmd = $_SERVER['argv'][1]; $this->waitingMsgFeature(false); $this->_preLauchingShell(false); - $Shell_Autocompletion = new Shell_Autocompletion($this->_commands, $this->_inlineArgCmds, $this->_outlineArgCmds, $this->_manCommands); - $Shell_Autocompletion->debug($this->_debug); - - $status = $Shell_Autocompletion->_($cmd); - - if($status) + if($_SERVER['argc'] === 2) { - $cmd = $Shell_Autocompletion->command; - $args = $Shell_Autocompletion->arguments; - - $this->_preRoutingShellCmd($cmd, $args); - $exit = $this->_routeShellCmd($cmd, $args); - $this->_postRoutingShellCmd($cmd, $args); - - echo json_encode($this->_lastCmdResult); + $cmd = $_SERVER['argv'][1]; + $status = $this->_routeCliCmdCall($cmd); - $exitCode = 0; + if($status) { + echo json_encode($this->_lastCmdResult); + $exitCode = 0; + } + else { + $this->error("Commande invalide", 'red', false, 'bold'); + $this->_SHELL->help(); + $exitCode = 1; + } } else { - Tools::e("Commande invalide", 'red', false, 'bold'); - $this->_SHELL->help(); - $exitCode = 1; + $exitCode = $this->_dispatchCliCall(); } $this->_postLauchingShell(false); @@ -132,33 +141,103 @@ protected function _oneShotCall() } } - protected function _preLauchingShell($welcomeMessage = true) + protected function _dispatchCliCall() { - $this->_moveToRoot(); + $this->_isOneShotCall = false; + $this->waitingMsgFeature(true); + + $options = getopt($this->_cliOptions['short'], $this->_cliOptions['long']); + + // Permet de garantir l'ordre d'exécution des commandes + foreach($this->_cliOptions['long'] as $cli) + { + $cli = str_replace(':', '', $cli); + + if(isset($options[$cli])) + { + $option = (array) $options[$cli]; + + foreach($option as $_option) + { + $status = $this->_cliOptToCmdArg($cli, $_option); + if(!$status) { + return 1; + } + } + } + } + + return 0; + } + + protected function _cliOptToCmdArg($cli, $option) + { + return 1; + } + + protected function _routeCliCmdCall($cmd) + { + $Shell_Autocompletion = new Shell_Autocompletion($this->_commands, $this->_inlineArgCmds, $this->_outlineArgCmds, $this->_manCommands); + $Shell_Autocompletion->debug($this->_debug); + + $status = $Shell_Autocompletion->_($cmd); + + if($status) + { + $cmd = $Shell_Autocompletion->command; + $args = $Shell_Autocompletion->arguments; + + $this->_preRoutingShellCmd($cmd, $args); + $this->_routeShellCmd($cmd, $args); + $this->_postRoutingShellCmd($cmd, $args); + return $this->_lastCmdStatus; + } + else { + return false; + } + } + + protected function _preLauchingShell($welcomeMessage = true) + { if($welcomeMessage) { - Tools::e(PHP_EOL.PHP_EOL."CTRL+C ferme le shell, utilisez ALT+C à la place", 'blue', false, 'italic'); - Tools::e(PHP_EOL."Utilisez UP et DOWN afin de parcourir votre historique de commandes", 'blue', false, 'italic'); - Tools::e(PHP_EOL."Utilisez TAB pour l'autocomplétion et ? afin d'obtenir davantage d'informations", 'blue', false, 'italic'); + $this->EOL(); + $this->print("CTRL+C ferme le shell, utilisez ALT+C à la place", 'blue', false, 'italic'); + $this->print("Utilisez UP et DOWN afin de parcourir votre historique de commandes", 'blue', false, 'italic'); + $this->print("Utilisez TAB pour l'autocomplétion et ? afin d'obtenir davantage d'informations", 'blue', false, 'italic'); + $this->EOL(); } } - abstract protected function _launchShell($welcomeMessage = true, $goodbyeMessage = true); + abstract protected function _launchShell(); protected function _postLauchingShell($goodbyeMessage = true) { if($goodbyeMessage) { - Tools::e(PHP_EOL.PHP_EOL."Merci d'avoir utilisé TOOLS-CLI by NOC", 'blue', false, 'italic'); + $this->EOL(); + $this->print("Merci d'avoir utilisé TOOLS-CLI by NOC", 'blue', false, 'italic'); + $this->EOL(); } } - protected function _preRoutingShellCmd($cmd, array &$args) + protected function _preRoutingShellCmd(&$cmd, array &$args) { + /** + * Dans certains cas, un espace peut être autocomplété à la fin de la commande afin de faciliter à l'utilisateur la CLI. + * Exemple: show => array('host', 'subnet') --> "show " afin que l'utilisateur puisse poursuivre la commande + * + * Cependant, si l'on souhaite autoriser "show" comme commande valide alors il faut nettoyer l'autocompletion + * + * Ce traitement est à réaliser pour les commandes OneShot, CLI et SHELL. + * De ce fait il ne faut pas le réaliser dans Shell_Abstract sinon les commandes OneShot ne seront pas nettoyées + */ + $cmd = rtrim($cmd, ' '); + foreach($args as &$arg) { $arg = preg_replace('#^("|\')|("|\')$#i', '', $arg); } - $this->displayWaitingMsg(); + $this->displayWaitingMsg(false, false); } protected function _routeShellCmd($cmd, array $args) @@ -166,98 +245,28 @@ protected function _routeShellCmd($cmd, array $args) switch($cmd) { case '': { - $this->deleteWaitingMsg(); - Tools::e("Tape help for help !", 'blue'); - break; - } - case 'ls': - case 'll': - { - $isPrinted = $this->_Service_Shell->printObjectInfos($args); - - if(!$isPrinted) { - $path = (isset($args[0])) ? ($args[0]) : (null); - $this->_Service_Shell->printObjectsList($path); - } - break; - } - case 'cd': - { - if(isset($args[0])) - { - $path = $args[0]; - $path = explode('/', $path); - - if($path[0] === "" || $path[0] === '~') { - array_shift($path); - $this->_moveToRoot(); - } - - $this->_moveToPath($path); - } - else { - $this->_moveToRoot(); - } - - $this->deleteWaitingMsg(); - break; - } - case 'pwd': - { - $currentPath = $this->_getCurrentPath(); - - $this->deleteWaitingMsg(); - $this->e($currentPath, 'white'); - $this->setLastCmdResult($currentPath); - break; - } - case 'cdautocomplete': - { - if(isset($args[0])) - { - switch($args[0]) - { - case 'en': - case 'enable': - $this->_cdautocomplete = true; - break; - case 'dis': - case 'disable': - $this->_cdautocomplete = false; - break; - } - } - else { - $this->_cdautocomplete = !$this->_cdautocomplete; - } - - if(!$this->_cdautocomplete) { - $this->_SHELL->setInlineArg('cd', $this->_inlineArgCmds['cd']); - } - - $cdAutoCompleteStatut = ($this->_cdautocomplete) ? ('activée') : ('désactivée'); - - $this->deleteWaitingMsg(); - Tools::e("L'autocomplétion de la commande CD est ".$cdAutoCompleteStatut, 'green'); + $this->print("Tape help for help !", 'blue'); break; } case 'history': { $this->deleteWaitingMsg(); $this->_SHELL->history(); + $this->EOL(); break; } case 'help': { $this->deleteWaitingMsg(); $this->_SHELL->help(); + $this->EOL(); break; } case 'exit': case 'quit': { + $this->deleteWaitingMsg(); return true; } default: { - $this->deleteWaitingMsg(); - Tools::e("Commande inconnue... [".$cmd."]", 'red'); + $this->error("Commande inconnue... [".$cmd."]", 'red'); } } @@ -266,58 +275,22 @@ protected function _routeShellCmd($cmd, array $args) protected function _postRoutingShellCmd($cmd, array $args) {} - protected function _setObjectAutocomplete(array $fields = null) - { - if($this->_cdautocomplete && count($fields) > 0) { - $options = $this->_Service_Shell->getOptions(); - $this->_SHELL->setInlineArg('cd', array(0 => $options)); - } - else { - $this->_SHELL->setInlineArg('cd', $this->_inlineArgCmds['cd']); - } - return $this; - } - - protected function _moveToRoot() - { - array_splice($this->_pathIds, 1); - array_splice($this->_pathApi, 1); - - $this->_Service_Shell->updatePath($this->_pathIds, $this->_pathApi); - - $this->_setObjectAutocomplete(); - $this->_SHELL->setShellPrompt('/'); - return $this->_pathApi[0]; - } - - protected function _moveToPath($path) - { - $this->browser($this->_pathIds, $this->_pathApi, $path); - $this->_Service_Shell->updatePath($this->_pathIds, $this->_pathApi); - - $this->_setObjectAutocomplete(); - $currentPath = $this->_getCurrentPath(); - $this->_SHELL->setShellPrompt($currentPath); - - return end($this->_pathApi); - } - - protected function _getCurrentPath() - { - $pathname = '/'; - - for($i=1; $i_pathApi); $i++) { - $pathname .= $this->_pathApi[$i]->getObjectLabel().'/'; - } - - return $pathname; - } - - public function displayWaitingMsg() + public function displayWaitingMsg($startEOL = true, $finishEOL = false, $infos = null) { - if($this->waitingMsgFeature()) { - $message = Tools::e("Veuillez patienter ...", 'orange', false, 'bold', true); - $this->_SHELL->printMessage($message); + if($this->waitingMsgFeature() && !$this->_waitingMsgState) + { + /** + * /!\ Ne pas inclure les sauts de lignes dans le traitement de la police + * $infos ne doit pas contenir de saut de lignes sinon la desactivation ne fonctionnera pas complètement + */ + $message = ($startEOL) ? (PHP_EOL) : (''); + + $message .= Tools::e("Veuillez patienter ...", 'orange', false, 'bold', true); + if($infos !== null) { $message .= Tools::e(' ('.$infos.')', 'orange', false, 'bold', true); } + + if($finishEOL) { $message .= PHP_EOL; } + $this->_SHELL->insertMessage($message); + $this->_waitingMsgState = true; return true; } else { @@ -325,10 +298,11 @@ public function displayWaitingMsg() } } - public function deleteWaitingMsg() + public function deleteWaitingMsg($lineUP = true) { - if($this->waitingMsgFeature()) { - $this->_SHELL->deleteMessage(); + if($this->waitingMsgFeature() && $this->_waitingMsgState) { + $this->_SHELL->deleteMessage(1, $lineUP); + $this->_waitingMsgState = false; return true; } else { @@ -350,11 +324,58 @@ public function setLastCmdResult($result) return $this; } - public function e($text, $textColor = false, $bgColor = false, $textStyle = false, $doNotPrint = false) + protected function _e($text, $textColor = false, $bgColor = false, $textStyle = false, $doNotPrint = false) { return ($this->_isOneShotCall) ? ($text) : (Tools::e($text, $textColor, $bgColor, $textStyle, $doNotPrint)); } + public function format($text, $textColor = 'green', $bgColor = false, $textStyle = false) + { + return $this->_e($text, $textColor, $bgColor, $textStyle, true); + } + + public function EOL($multiplier = 1, $textColor = false, $bgColor = false, $textStyle = false, $autoDelWaitingMsg = true) + { + if($autoDelWaitingMsg) { + $this->deleteWaitingMsg(); + } + + $this->_e(str_repeat(PHP_EOL, $multiplier), $textColor, $bgColor, $textStyle, false); + return $this; // /!\ Important + } + + public function print($text, $textColor = 'green', $bgColor = false, $textStyle = false, $autoDelWaitingMsg = true) + { + if($autoDelWaitingMsg) { + $this->deleteWaitingMsg(); + } + + /** + * /!\ Ne doit pas être formaté comme le texte + * /!\ Ne pas supprimer le message d'attente: + * - Déjà traité dans cette méthode + * - Si $autoDelWaitingMsg === false + */ + $this->EOL(1, false, false, false, false); + return $this->_e($text, $textColor, $bgColor, $textStyle, false); + } + + public function error($text, $textColor = 'red', $bgColor = false, $textStyle = false, $autoDelWaitingMsg = true) + { + if($autoDelWaitingMsg) { + $this->deleteWaitingMsg(); + } + + /** + * /!\ Ne doit pas être formaté comme le texte + * /!\ Ne pas supprimer le message d'attente: + * - Déjà traité dans cette méthode + * - Si $autoDelWaitingMsg === false + */ + $this->EOL(1, false, false, false, false); + return $this->_e($text, $textColor, $bgColor, $textStyle, false); + } + protected function _throwException(Exception $exception) { Tools::e(PHP_EOL.PHP_EOL."Exception --> ".$exception->getMessage()." [".$exception->getFile()."] {".$exception->getLine()."}", 'red'); diff --git a/services/browser.php b/services/browser.php new file mode 100644 index 0000000..4db9a12 --- /dev/null +++ b/services/browser.php @@ -0,0 +1,151 @@ +_moveToRoot(); + } + + protected function _routeShellCmd($cmd, array $args) + { + switch($cmd) + { + case 'ls': + case 'll': + { + $isPrinted = $this->_Service_Shell->printObjectInfos($args, true); + + if(!$isPrinted || $this->_printBothObjectAndList) + { + if(!$isPrinted) { + $this->deleteWaitingMsg(true); // Fix PHP_EOL lié au double message d'attente successif lorsque la commande precedente n'a rien affichée + } + + $path = (isset($args[0])) ? ($args[0]) : (null); + $objects = $this->_Service_Shell->printObjectsList($path); + $this->setLastCmdResult($objects); + } + break; + } + case 'cd': + { + if(isset($args[0])) + { + $path = $args[0]; + $path = explode('/', $path); + + if($path[0] === "" || $path[0] === '~') { + array_shift($path); + $this->_moveToRoot(); + } + + $this->_moveToPath($path); + } + else { + $this->_moveToRoot(); + } + + $this->deleteWaitingMsg(); + break; + } + case 'pwd': + { + $currentPath = $this->_getCurrentPath(); + + $this->print($currentPath, 'white'); + $this->setLastCmdResult($currentPath); + break; + } + case 'cdautocomplete': + { + if(isset($args[0])) + { + switch($args[0]) + { + case 'en': + case 'enable': + $this->_cdautocomplete = true; + break; + case 'dis': + case 'disable': + $this->_cdautocomplete = false; + break; + } + } + else { + $this->_cdautocomplete = !$this->_cdautocomplete; + } + + if(!$this->_cdautocomplete) { + $this->_SHELL->setInlineArg('cd', $this->_inlineArgCmds['cd']); + } + + $cdAutoCompleteStatut = ($this->_cdautocomplete) ? ('activée') : ('désactivée'); + $this->print("L'autocomplétion de la commande CD est ".$cdAutoCompleteStatut, 'green'); + break; + } + default: { + return parent::_routeShellCmd($cmd, $args); + } + } + + return false; + } + + protected function _setObjectAutocomplete(array $fields = null) + { + if($this->_cdautocomplete && count($fields) > 0) { + $options = $this->_Service_Shell->getOptions(); + $this->_SHELL->setInlineArg('cd', array(0 => $options)); + } + else { + $this->_SHELL->setInlineArg('cd', $this->_inlineArgCmds['cd']); + } + return $this; + } + + protected function _moveToRoot() + { + array_splice($this->_pathIds, 1); + array_splice($this->_pathApi, 1); + + $this->_Service_Shell->updatePath($this->_pathIds, $this->_pathApi); + + $this->_setObjectAutocomplete(); + $this->_SHELL->setShellPrompt('/'); + return $this->_pathApi[0]; + } + + protected function _moveToPath($path) + { + $this->browser($this->_pathIds, $this->_pathApi, $path); + $this->_Service_Shell->updatePath($this->_pathIds, $this->_pathApi); + + $this->_setObjectAutocomplete(); + $currentPath = $this->_getCurrentPath(); + $this->_SHELL->setShellPrompt($currentPath); + + return end($this->_pathApi); + } + + protected function _getCurrentPath() + { + $pathname = '/'; + + for($i=1; $i_pathApi); $i++) { + $pathname .= $this->_pathApi[$i]->getObjectLabel().'/'; + } + + return $pathname; + } + } \ No newline at end of file diff --git a/services/dcim.php b/services/dcim.php index 82b5862..1a47420 100644 --- a/services/dcim.php +++ b/services/dcim.php @@ -1,21 +1,21 @@ _DCIM = $DCIM->getDcim(); Dcim_Api_Abstract::setDcim($this->_DCIM); - $this->_Service_Shell = new Service_Shell_Dcim($this); + $this->_Service_Shell = new Service_Shell_Dcim($this, $this->_SHELL); if($autoInitialisation) { $this->_init(); } } - protected function _launchShell($welcomeMessage = true, $goodbyeMessage = true) + protected function _launchShell() { $exit = false; - $this->_preLauchingShell($welcomeMessage); while(!$exit) { @@ -125,8 +124,6 @@ protected function _launchShell($welcomeMessage = true, $goodbyeMessage = true) $exit = $this->_routeShellCmd($cmd, $args); $this->_postRoutingShellCmd($cmd, $args); } - - $this->_postLauchingShell($goodbyeMessage); } protected function _routeShellCmd($cmd, array $args) @@ -172,8 +169,8 @@ protected function _routeShellCmd($cmd, array $args) $jnlpUrl = $this->_DCIM->getJnlpUrl(64); $status = file_put_contents($jnlp, fopen($jnlpUrl, 'r')); - if(!$status) { - Tools::e("Impossible de télécharger le JNLP [".$jnlpUrl."]", 'red'); + if($status === false) { + $this->error("Impossible de télécharger le JNLP [".$jnlpUrl."]", 'red'); break; } } @@ -188,10 +185,19 @@ protected function _routeShellCmd($cmd, array $args) } } - if(isset($status) && !$status) { - $this->deleteWaitingMsg(); - $msg = Tools::e($this->_manCommands[$cmd], 'red', 'normal', false, true); - $this->_SHELL->printMessage($msg); + if(isset($status)) + { + $this->_lastCmdStatus = $status; + + if(!$status && !$this->_isOneShotCall) + { + if(array_key_exists($cmd, $this->_manCommands)) { + $this->error($this->_manCommands[$cmd], 'red'); + } + else { + $this->error("Une erreur s'est produit lors de l'exécution de cette commande", 'red'); + } + } } return $exit; @@ -208,8 +214,8 @@ protected function _setObjectAutocomplete(array $fields = null) protected function _moveToRoot() { if($this->_pathIds === null || $this->_pathApi === null) { - $this->_pathIds[] = Dcim_Api_Location::getRootLocationId(); - $this->_pathApi[] = new Dcim_Api_Location(end($this->_pathIds)); + $this->_pathIds[] = null; + $this->_pathApi[] = new Dcim_Api_Location(); } return parent::_moveToRoot(); diff --git a/services/shell/abstract.php b/services/shell/abstract.php index b5c0a41..717a502 100644 --- a/services/shell/abstract.php +++ b/services/shell/abstract.php @@ -2,142 +2,58 @@ abstract class Service_Shell_Abstract { protected $_MAIN; + protected $_SHELL; + protected $_CONFIG; - protected $_pathIds; - protected $_pathApi; - protected $_searchfromCurrentPath = true; - - - public function __construct(Service_Abstract $MAIN) + public function __construct(Service_Abstract $MAIN, SHELL $SHELL) { $this->_MAIN = $MAIN; + $this->_SHELL = $SHELL; + $this->_CONFIG = CONFIG::getInstance(); } - public function updatePath(array $pathIds, array $pathApi) - { - $this->_pathIds = $pathIds; - $this->_pathApi = $pathApi; - return $this; - } - - protected function _browser($path = null, $returnCurrentApi = true) - { - $pathIds = $this->_pathIds; - $pathApi = $this->_pathApi; - - if($path !== null) { - // /!\ browser modifie pathIds et pathApi, passage par référence - $this->_MAIN->browser($pathIds, $pathApi, $path); - } - - return ($returnCurrentApi) ? (end($pathApi)) : ($pathApi); - } - - // @todo optimiser garder en cache en fct path - abstract protected function _getObjects($path = null); + // @todo optimiser garder en cache en fonction de context + abstract protected function _getObjects($context = null); - public function getOptions($path = null) + /** + * Affiche les informations d'un seul type d'éléments ou d'objets + * Le code doit pouvoir fonctionner sur un tableau simple ou sur un tableau d'objets + */ + protected function _printInformations($type, $items, $title = false) { - $options = array(); - $objects = $this->_getObjects($path); - - foreach($objects as $type => $list) + if($items !== false && Tools::is('array&&count>0', $items)) { - if(count($list) > 0) - { - foreach($list as $fields) - { - if(array_key_exists($type, $this->_OPTION_FIELDS)) { - $optFields = array_flip($this->_OPTION_FIELDS[$type]['fields']); - $option = array_intersect_key($fields, $optFields); - $options = array_merge($options, array_values($option)); - } - } - } - } - - return $options; - } - - public function printObjectsList($path = null) - { - $objects = $this->_getObjects($path); - $this->_MAIN->deleteWaitingMsg(); - $objects = $this->_printObjectsList($objects); - $this->_MAIN->setLastCmdResult($objects); - return true; - } + $results = array(); - protected function _printObjectsList(array $objects) - { - foreach($objects as $type => &$list) - { - if(count($list) > 0) + if($title === false) { - $this->_MAIN->e(PHP_EOL.$this->_LIST_TITLES[$type], 'black', 'white', 'bold'); - - foreach($list as &$fields) { - $fields = array_intersect_key($fields, array_flip($this->_LIST_FIELDS[$type]['fields'])); - $fields = vsprintf($this->_LIST_FIELDS[$type]['format'], $fields); + if(array_key_exists($type, $this->_PRINT_TITLES)) { + $title = $this->_PRINT_TITLES[$type]; } - - $this->_MAIN->e(PHP_EOL.implode(PHP_EOL, $list).PHP_EOL, 'grey'); - } - } - - return $objects; - } - - abstract public function printObjectInfos(array $args, $fromCurrentPath = true); - - protected function _printObjectInfos(array $cases, array $args, $fromCurrentPath = true) - { - if(isset($args[0])) - { - foreach($cases as $type => $method) - { - $infos = $this->{$method}($args[0], $fromCurrentPath); - - if(count($infos) > 0) { - $objectType = $type; - break; + else { + $title = 'INFORMATIONS'; } } - if(isset($objectType)) { - $status = $this->_printInformations($objectType, $infos); - return array($status, $objectType, $infos); - } - else { - return false; - } - } - else { - return false; - } - } - - protected function _printInformations($type, $items) - { - $this->_MAIN->deleteWaitingMsg(); - - if($items !== false && Tools::is('array&&count>0', $items)) - { - $results = array(); - $this->_MAIN->e(PHP_EOL.'INFORMATIONS', 'black', 'white', 'bold'); + $this->_MAIN->EOL()->print($title, 'black', 'white', 'bold'); - foreach($items as $item) + /** + * /!\ item peut être un objet donc il faut que le code qui le concerne puisse fonctionner sur un objet + * Par exemple: array_key_exists ne peut pas fonctionner, mais isset oui grâce à __isset + */ + foreach($items as $index => $item) { /** - * Il faut réinitialiser $infos pour chaque item + * Il faut réinitialiser $infos pour chaque item * Permet aussi de garder l'ordre de _PRINT_FIELDS */ $infos = array(); foreach($this->_PRINT_FIELDS[$type] as $key => $format) { - if(array_key_exists($key, $item)) + // /!\ Code compatible array et object ! + if((is_array($item) && array_key_exists($key, $item)) || isset($item[$key])) { $field = $item[$key]; $field = vsprintf($format, $field); @@ -145,7 +61,7 @@ protected function _printInformations($type, $items) switch($key) { case 'header': - $field = $this->_MAIN->e($field, 'green', false, 'bold', true); + $field = $this->_MAIN->format($field, 'green', false, 'bold'); break; } @@ -155,54 +71,97 @@ protected function _printInformations($type, $items) if(count($infos) > 0) { $results[] = $infos; - $this->_MAIN->e(PHP_EOL.PHP_EOL.implode(PHP_EOL, $infos), 'grey'); + $this->_MAIN->EOL()->print(implode(PHP_EOL, $infos), 'grey'); } } + $this->_MAIN->EOL(); $this->_MAIN->setLastCmdResult($results); return true; } + else { + $this->_MAIN->error("Aucun élément à afficher", 'orange'); + } return false; } - protected function _getLastApiPath(array $pathApi, $apiClassName) - { - $pathApi = array_reverse($pathApi); + abstract public function printObjectInfos(array $args, $fromCurrentContext = true); - foreach($pathApi as $api) + /** + * Récupère les informations d'un seul type d'éléments ou d'objets puis les affiche + * Le code doit pouvoir fonctionner sur un tableau simple ou sur un tableau d'objets + */ + protected function _printObjectInfos(array $cases, array $args, $fromCurrentContext = true) + { + if(isset($args[0])) { - if(get_class($api) === $apiClassName) { - return $api; + foreach($cases as $type => $method) + { + $objects = $this->{$method}($args[0], $fromCurrentContext); + + if(count($objects) > 0) { + $objectType = $type; + break; + } + } + + if(isset($objectType)) { + $status = $this->_printInformations($objectType, $objects); + return array($status, $objectType, $objects); } } + $this->_MAIN->deleteWaitingMsg(); // Garanti la suppression du message return false; } - protected function _arrayFilter(array $items, array $fields) + /** + * Récupère les informations de tous les éléments ou objets puis les affiche + */ + public function printObjectsList($context = null) { - $results = array(); + $this->_MAIN->displayWaitingMsg(); + $objects = $this->_getObjects($context); + return $this->_printObjectsList($objects); + } - foreach($items as $item) + /** + * Affiche les informations de plusieurs types d'éléments ou d'objets + * Le code doit pouvoir fonctionner sur un tableau simple ou sur un tableau d'objets + */ + protected function _printObjectsList(array $objects) + { + foreach($objects as $type => &$items) { - if(count($item) > 0) + if(count($items) > 0) { - $result = array(); + $this->_MAIN->EOL()->print($this->_LIST_TITLES[$type], 'black', 'white', 'bold'); - foreach($fields as $field) + $items = Tools::arrayFilter($items, $this->_LIST_FIELDS[$type]['fields']); + + foreach($items as &$item) { - if(array_key_exists($field, $item)) { - $result[$field] = $item[$field]; + /** + * /!\ L'ordre de base dans item est conservé ce qui rend le résultat incertain + * Préférer l'utilisation de la méthode Tools::arrayFilter qui filtre et garanti l'ordre + */ + //$item = array_intersect_key($item, array_flip($this->_LIST_FIELDS[$type]['fields'])); + + $item = vsprintf($this->_LIST_FIELDS[$type]['format'], $item); + + $item = preg_replace_callback("#([^\t]*)(\t+)#i", function(array $matches) { + return $matches[1].Tools::t($matches[1], "\t", mb_strlen($matches[2]), 0, 8); } + , $item); } - if(count($result) > 0) { - $results[] = $result; - } + $this->_MAIN->EOL()->print(implode(PHP_EOL, $items), 'grey'); + $this->_MAIN->EOL(); } } - return $results; + $this->_MAIN->deleteWaitingMsg(); // Garanti la suppression du message + return $objects; } } \ No newline at end of file diff --git a/services/shell/browser.php b/services/shell/browser.php new file mode 100644 index 0000000..429e64f --- /dev/null +++ b/services/shell/browser.php @@ -0,0 +1,66 @@ +_pathIds = $pathIds; + $this->_pathApi = $pathApi; + return $this; + } + + protected function _browser($path = null, $returnCurrentApi = true) + { + $pathIds = $this->_pathIds; + $pathApi = $this->_pathApi; + + if($path !== null) { + // /!\ browser modifie pathIds et pathApi, passage par référence + $this->_MAIN->browser($pathIds, $pathApi, $path); + } + + return ($returnCurrentApi) ? (end($pathApi)) : ($pathApi); + } + + public function getOptions($path = null) + { + $options = array(); + $objects = $this->_getObjects($path); + + foreach($objects as $type => $list) + { + if(count($list) > 0) + { + foreach($list as $fields) + { + if(array_key_exists($type, $this->_OPTION_FIELDS)) { + $optFields = array_flip($this->_OPTION_FIELDS[$type]['fields']); + $option = array_intersect_key($fields, $optFields); + $options = array_merge($options, array_values($option)); + } + } + } + } + + return $options; + } + + protected function _getLastApiPath(array $pathApi, $apiClassName) + { + $pathApi = array_reverse($pathApi); + + foreach($pathApi as $api) + { + if(get_class($api) === $apiClassName) { + return $api; + } + } + + return false; + } + } \ No newline at end of file diff --git a/services/shell/dcim.php b/services/shell/dcim.php index fb6b774..fbea2cd 100644 --- a/services/shell/dcim.php +++ b/services/shell/dcim.php @@ -1,7 +1,7 @@ array( @@ -41,6 +41,13 @@ class Service_Shell_Dcim extends Service_Shell_Abstract ) ); + protected $_PRINT_TITLES = array( + 'location' => 'LOCATIONS', + 'cabinet' => 'CABINETS', + 'equipment' => 'EQUIPMENTS', + 'cable' => 'CABLES', + ); + protected $_PRINT_FIELDS = array( 'location' => array( 'header' => '%s', @@ -65,9 +72,13 @@ class Service_Shell_Dcim extends Service_Shell_Abstract ), ); + protected $_searchfromCurrentPath = true; + - protected function _getObjects($path = null) + protected function _getObjects($context = null) { + $path = $context; + $items = array( 'Dcim_Api_Location' => array(), 'Dcim_Api_Cabinet' => array(), @@ -195,7 +206,7 @@ protected function _getObjects($path = null) ); } - public function printObjectInfos(array $args, $fromCurrentPath = true) + public function printObjectInfos(array $args, $fromCurrentContext = true) { // /!\ ls AUB --> On ne doit pas afficher AUB mais le contenu de AUB ! /*$objectApi = end($this->_pathApi); @@ -222,15 +233,19 @@ public function printObjectInfos(array $args, $fromCurrentPath = true) 'equipment' => '_getEquipmentInfos' ); - $result = $this->_printObjectInfos($cases, $args, $fromCurrentPath); + $result = $this->_printObjectInfos($cases, $args, $fromCurrentContext); if($result !== false) { list($status, $objectType, $infos) = $result; - if($status && $objectType === 'equipment') { + /** + * /!\ Attention aux doublons lorsque printObjectsList est appelé manuellement + * Voir code pour ls ou ll dans services/browser méthode _routeShellCmd + */ + /*if($status && $objectType === 'equipment') { $this->printEquipmentExtra($infos); - } + }*/ return $status; } @@ -247,7 +262,7 @@ public function printLocationInfos(array $args, $fromCurrentPath = true, $recurs $status = $this->_printInformations('location', $infos); if($status === false) { - Tools::e("Localisation introuvable", 'orange'); + $this->_MAIN->error("Localisation introuvable", 'orange'); } return true; @@ -264,7 +279,7 @@ public function printCabinetInfos(array $args, $fromCurrentPath = true, $recursi $status = $this->_printInformations('cabinet', $infos); if($status === false) { - Tools::e("Baie introuvable", 'orange'); + $this->_MAIN->error("Baie introuvable", 'orange'); } elseif(count($infos) === 1) { @@ -280,13 +295,9 @@ public function printCabinetInfos(array $args, $fromCurrentPath = true, $recursi } } - $this->_MAIN->displayWaitingMsg(); - // @todo $full affiche tous les U de la baie $path = $infos[0]['path'].'/'.$infos[0]['name']; - $objects = $this->_getObjects($path); - $this->_MAIN->deleteWaitingMsg(); - $this->_printObjectsList($objects); + $this->printObjectsList($path); } return true; @@ -303,7 +314,7 @@ public function printEquipmentInfos(array $args, $fromCurrentPath = true, $recur $status = $this->_printInformations('equipment', $infos); if($status === false) { - Tools::e("Equipement introuvable", 'orange'); + $this->_MAIN->error("Equipement introuvable", 'orange'); } else { $this->printEquipmentExtra($infos); @@ -317,18 +328,13 @@ public function printEquipmentInfos(array $args, $fromCurrentPath = true, $recur protected function printEquipmentExtra(array $infos) { - if(count($infos) === 1) - { - $this->_MAIN->displayWaitingMsg(); - + if(count($infos) === 1) { $path = $infos[0]['path'].'/'.$infos[0]['name']; - $objects = $this->_getObjects($path); - $this->_MAIN->deleteWaitingMsg(); - $this->_printObjectsList($objects); + $this->printObjectsList($path); } } - protected function _getLocationInfos($location, $fromCurrentPath, $path = null, $recursion = false) + protected function _getLocationInfos($location, $fromCurrentPath = true, $path = null, $recursion = false) { $items = array(); $locations = array(); @@ -362,7 +368,7 @@ protected function _getLocationInfos($location, $fromCurrentPath, $path = null, return $items; } - protected function _getCabinetInfos($cabinet, $fromCurrentPath, $path = null, $recursion = false) + protected function _getCabinetInfos($cabinet, $fromCurrentPath = true, $path = null, $recursion = false) { $items = array(); $cabinets = array(); @@ -396,7 +402,7 @@ protected function _getCabinetInfos($cabinet, $fromCurrentPath, $path = null, $r return $items; } - protected function _getEquipmentInfos($equipment, $fromCurrentPath, $path = null, $recursion = false) + protected function _getEquipmentInfos($equipment, $fromCurrentPath = true, $path = null, $recursion = false) { $items = array(); $equipments = array(); @@ -449,21 +455,17 @@ public function printSearchObjects(array $args) $objects = $this->_searchObjects($args[0], $args[1], $args[2]); $time2 = microtime(true); - $this->_MAIN->deleteWaitingMsg(); - if($objects !== false) { $this->_MAIN->setLastCmdResult($objects); - $this->_MAIN->e(PHP_EOL.'RECHERCHE ('.round($time2-$time1).'s)', 'black', 'white', 'bold'); + $this->_MAIN->print('RECHERCHE ('.round($time2-$time1).'s)', 'black', 'white', 'bold'); if(!$this->_MAIN->isOneShotCall()) { if(isset($objects['locations'])) { - $this->_MAIN->e(PHP_EOL); - $counter = count($objects['locations']); - $this->_MAIN->e(PHP_EOL.'LOCATIONS ('.$counter.')', 'black', 'white'); + $this->_MAIN->EOL()->print('LOCATIONS ('.$counter.')', 'black', 'white'); if($counter > 0) { @@ -472,20 +474,18 @@ public function printSearchObjects(array $args) $text1 = '['.$location['path'].']'; $text1 .= Tools::t($text1, "\t", 2, 0, 8); $text2 = $location['header']; - Tools::e(PHP_EOL.$text1.$text2, 'grey'); + $this->_MAIN->print($text1.$text2, 'grey'); } } else { - Tools::e(PHP_EOL.'Aucun résultat', 'orange'); + $this->_MAIN->error('Aucun résultat', 'orange'); } } if(isset($objects['cabinets'])) { - $this->_MAIN->e(PHP_EOL); - $counter = count($objects['cabinets']); - $this->_MAIN->e(PHP_EOL.'CABINETS ('.$counter.')', 'black', 'white'); + $this->_MAIN->EOL()->print('CABINETS ('.$counter.')', 'black', 'white'); if($counter > 0) { @@ -494,20 +494,18 @@ public function printSearchObjects(array $args) $text1 = '['.$cabinet['path'].']'; $text1 .= Tools::t($text1, "\t", 2, 0, 8); $text2 = $cabinet['header']; - Tools::e(PHP_EOL.$text1.$text2, 'grey'); + $this->_MAIN->print($text1.$text2, 'grey'); } } else { - Tools::e(PHP_EOL.'Aucun résultat', 'orange'); + $this->_MAIN->error('Aucun résultat', 'orange'); } } if(isset($objects['equipments'])) { - $this->_MAIN->e(PHP_EOL); - $counter = count($objects['equipments']); - $this->_MAIN->e(PHP_EOL.'EQUIPMENTS ('.$counter.')', 'black', 'white'); + $this->_MAIN->EOL()->print('EQUIPMENTS ('.$counter.')', 'black', 'white'); if($counter > 0) { @@ -518,17 +516,19 @@ public function printSearchObjects(array $args) $text2 = $equipment['templateName']; $text2 .= Tools::t($text2, "\t", 4, 0, 8); $text3 = $equipment['header'].' {'.$equipment['serialNumber'].'}'; - Tools::e(PHP_EOL.$text1.$text2.$text3, 'grey'); + $this->_MAIN->print($text1.$text2.$text3, 'grey'); } } else { - Tools::e(PHP_EOL.'Aucun résultat', 'orange'); + $this->_MAIN->error('Aucun résultat', 'orange'); } } + + $this->_MAIN->EOL(); } } else { - Tools::e("Aucun résultat", 'orange'); + $this->_MAIN->error("Aucun résultat trouvé", 'orange'); } return true;