diff --git a/cmake/version.cmake b/cmake/version.cmake index bd9cdeb..266d101 100644 --- a/cmake/version.cmake +++ b/cmake/version.cmake @@ -3,7 +3,7 @@ # set (TK_UTIL_MAJOR_VERSION "6") -set (TK_UTIL_MINOR_VERSION "9") +set (TK_UTIL_MINOR_VERSION "10") set (TK_UTIL_RELEASE_VERSION "0") set (TK_UTIL_VERSION ${TK_UTIL_MAJOR_VERSION}.${TK_UTIL_MINOR_VERSION}.${TK_UTIL_RELEASE_VERSION}) diff --git a/src/TkUtil/CMakeLists.txt b/src/TkUtil/CMakeLists.txt index 591c5de..fc4bb77 100644 --- a/src/TkUtil/CMakeLists.txt +++ b/src/TkUtil/CMakeLists.txt @@ -30,7 +30,7 @@ foreach (lib ${ALL_TARGETS}) endforeach (lib) target_link_libraries (TkUtil PUBLIC ${Iconv_LIBRARIES}) target_include_directories (TkUtil PUBLIC $$) -target_link_libraries (TkUtil PUBLIC pthread) +target_link_libraries (TkUtil PUBLIC stdc++fs pthread) # INSTALLATION : include(CMakePackageConfigHelpers) diff --git a/src/TkUtil/File.cpp b/src/TkUtil/File.cpp index 2a4285c..7015286 100644 --- a/src/TkUtil/File.cpp +++ b/src/TkUtil/File.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include USING_STD @@ -245,6 +245,28 @@ bool File::isExecutable ( ) const } // File::isExecutable +void File::getChildren (std::vector& directories, std::vector& files) const // v 6.10.0 +{ // API C++ 17 + directories.clear ( ); + files.clear ( ); + + if (false == isDirectory ( )) + { + UTF8String message (charset); + message << "Impossibilité de donner la liste des sous-répertoires et fichiers : " << getFullFileName ( ) << " n'est pas un répertoire."; + throw Exception (message); + } // if (false == isDirectory ( )) + + for (const auto& entry : filesystem::directory_iterator (getFullFileName ( ))) + { + if (true == filesystem::is_directory (entry)) + directories.push_back (File (filesystem::path (entry))); + else if (true == filesystem::is_regular_file (entry)) + files.push_back (File (filesystem::path (entry))); + } // for (const auto& entry : filesystem::directory_iterator (getFullFileName ( ))) +} // File::getChildren + + mode_t File::getAccessRights ( ) const // v 5.11.0 { errno = 0; diff --git a/src/TkUtil/Process.cpp b/src/TkUtil/Process.cpp index 7398e32..70588cd 100644 --- a/src/TkUtil/Process.cpp +++ b/src/TkUtil/Process.cpp @@ -326,11 +326,12 @@ void Process::execute (bool autoDelete) int Process::wait ( ) { if (true == isCompleted ( )) - { + return getCompletionCode ( ); // v 6.10.0 +/* { UTF8String errorMsg (charset); errorMsg << "Impossibilité d'attendre la fin du processus " << getName ( ) << " : processus terminé."; throw Exception (errorMsg); - } // if (true == isCompleted ( )) + } // if (true == isCompleted ( )) */ setWaited (true); pid_t childPid = getPid ( ); int status = -1; @@ -446,9 +447,7 @@ void Process::initialize (char* envp []) string Process::getChildLine ( ) { if ((true == isCompleted ( )) && (0 == _childBuffer.length ( ))) - { // v 2.21.0 : le remplissage du buffer n'est plus effectué dans - // childDeath (accès concurrents depuis la même pile aux fonctions de - // la lib malloc). + { // v 2.21.0 : le remplissage du buffer n'est plus effectué dans childDeath (accès concurrents depuis la même pile aux fonctions de la lib malloc). try { fillChildBuffer ( ); diff --git a/src/TkUtil/public/TkUtil/File.h b/src/TkUtil/public/TkUtil/File.h index aacc1b0..6ca68fd 100644 --- a/src/TkUtil/public/TkUtil/File.h +++ b/src/TkUtil/public/TkUtil/File.h @@ -6,6 +6,7 @@ #include #include #include +#include BEGIN_NAMESPACE_UTIL @@ -120,22 +121,30 @@ class File * @return true si le fichier est accessible en exécution, sinon false. */ virtual bool isExecutable ( ) const; + + /** + * @return La liste des sous-répertoires (exception faite de "." et "..") et fichiers. + * @exception Une exception est levée en cas d'erreur, notamment si l'instance n'est pas un répertoire. + * @since 6.10.0 + */ + virtual void getChildren (std::vector& directories, std::vector& files) const; /** * @return Les droits d'accès sur le fichier (champ st_mode de la structure stat). - * Combinaison par opérateur | des flags S_IR*, S_IW*, S_IX*, * pouvant prendre pour - * valeurs USR, GRP, OTH (cf. man chmod). + * Combinaison par opérateur | des flags S_IR*, S_IW*, S_IX*, * pouvant prendre pour valeurs USR, GRP, OTH (cf. man chmod). * @exception Une exception est levée en cas d'erreur. * @see setAccessRights + * @since 5.11.0 */ - virtual mode_t getAccessRights ( ) const; // v 5.11.0 + virtual mode_t getAccessRights ( ) const; /** * @param Nouveaux droits d'accès sur le fichier (champ st_mode de la structure stat). * @exception Une exception est levée en cas d'erreur. * @see getAccessRights + * @since 5.11.0 */ - virtual void setAccessRights (mode_t rigths); // v 5.11.0 + virtual void setAccessRights (mode_t rigths); /** * Créé effectivement le fichier si celui-ci n'existe pas. Créé l'arborescence parente si nécessaire. @@ -154,11 +163,11 @@ class File * Déplace physiquement le fichier. * @param Nouveau path du fichier. * @param Si true détruit l'éventuel fichier ayant le path demandé. - * Si false et qu'un fichier existe déjà alors lève une exception. + * Si false et qu'un fichier existe déjà alors lève une exception. * @exception Une exception est levée en cas d'impossibilité de déplacer le fichier. * @see setFullFileName */ - virtual void rename (const std::string& newpath, bool erase); // v 5.4.0 + virtual void rename (const std::string& newpath, bool erase); // v 5.4.0 /** * Détruit le fichier s'il existe. @@ -173,16 +182,14 @@ class File virtual void print (IN_STD ostream& stream) const; /** - * @return Le masque de permissions utilisé lors de la création de - * fichiers. + * @return Le masque de permissions utilisé lors de la création de fichiers. */ static mode_t getUMask ( ); /** * Créé un nom unique de fichier temporaire. * @param Préfix du nom de fichier temporaire. - * @param true si le fichier doit être créé dans le répertoire des fichiers temporaires, - * false si il doit être créé en relatif par rapport à prefix. + * @param true si le fichier doit être créé dans le répertoire des fichiers temporaires, false si il doit être créé en relatif par rapport à prefix. * @exception Une exception est levée en cas d'échec. */ static IN_STD string createTemporaryName (const IN_STD string& prefix, bool inTmpDir = true); diff --git a/src/TkUtil/public/TkUtil/Process.h b/src/TkUtil/public/TkUtil/Process.h index 62c6c41..22e0a74 100644 --- a/src/TkUtil/public/TkUtil/Process.h +++ b/src/TkUtil/public/TkUtil/Process.h @@ -79,6 +79,30 @@ BEGIN_NAMESPACE_UTIL * // ...
* }
*
+ * 3- Lecture de la sortie standard du processus lancé (cf. src/tests/process.cpp) :
+ * + * unique_ptr process (new Process ("ls")); + * process->getOptions ( ).addOption ("-al"); + * process->getOptions ( ).addOption (argv [1]); + * cout << "Cmd line is : " << process->getCommandLine ( ) << endl; + * process->enableChildToSonCommunications (true); + * process->execute (false); + * const int status = process->wait ( ); + * cout << "Process standard output :" << endl; + * bool completed = false; + * while (false == completed) + * { + * try + * { + * const string output = process->getChildLine ( ); + * cout << output << endl; + * } + * catch (...) + * { + * completed = true; + * } + * } // while (false == completed) + *
*

*

Cette classe permet également de connaître le répertoire courrant de l'application à l'aide de la méthode statique getCurrentDirectory. *

@@ -141,8 +165,7 @@ class Process Process (const IN_STD string& processName); /** - * Destructeur : appelé automatiquement par l'instance en fin d'exécution - * si true est passé en argument d'execute . + * Destructeur : appelé automatiquement par l'instance en fin d'exécution si true est passé en argument d'execute . * @see execute */ virtual ~Process ( ); @@ -150,7 +173,7 @@ class Process /** * Créé une instance à partir de la ligne de commande transmise en argument (exécutable puis arguments). * @return instance créée. - * @todo possibilité de déclarer des variables d'environnement avant l'exécutable avec la synatxe variable=valeur + * @todo possibilité de déclarer des variables d'environnement avant l'exécutable avec la syntaxe variable=valeur */ static Process* create (const std::string& cmdLine); // v 6.2.0 @@ -160,8 +183,7 @@ class Process virtual ProcessOptions& getOptions ( ); /** - * @return La ligne de commande complète qui sera exécutée. A des - * fins de débogage, méthode non utilisée par execute. + * @return La ligne de commande complète qui sera exécutée. A des fins de débogage, méthode non utilisée par execute. */ virtual IN_STD string getCommandLine ( ); @@ -173,8 +195,8 @@ class Process virtual void execute (bool autoDelete = true); /** - * Attend la fin du processus fils. - * @return status de retour du processus fils. + * Attend si nécessaire la fin du processus fils. + * @return status de retour du processus fils (getCompletionCode ( )). * @see getCompletionCode * @see getErrorMessage */ @@ -224,16 +246,12 @@ class Process * @see getCompletionCode * @see isCompleted */ -// virtual const IN_STD string& getErrorMessage ( ) const // v 4.4.0 -// { return _errorMessage; } - virtual const IN_STD string getErrorMessage ( ) const // v 4.4.0 + virtual const IN_STD string getErrorMessage ( ) const { return std::string (_errorMessage); } /** - * A invoquer si un pipe doit être ouvert de la sortie standard du - * processus fils vers le processus père. - * @param true si la communication doit être en mode bloquant, false - * dans le cas contraire. Le mode non bloquant est irréversible. + * A invoquer si un pipe doit être ouvert de la sortie standard du processus fils vers le processus père. + * @param true si la communication doit être en mode bloquant, false dans le cas contraire. Le mode non bloquant est irréversible. * @exception Lève une exception en cas d'erreur * @see getpipeDescriptors * @see getChildLine @@ -241,8 +259,7 @@ class Process void enableChildToSonCommunications (bool blocking = true); /** - * @return true si un pipe doit être ouvert de la sortie standard du - * processus fils vers le processus père. + * @return true si un pipe doit être ouvert de la sortie standard du processus fils vers le processus père. * @see enableChildToSonCommunications */ bool isChildToSonCommunicationsEnabled ( ) const @@ -279,8 +296,7 @@ class Process * int main (int argc, char* argv[], char* envp []) * @warning il est essentiel d'appeler cette fonction avant le lancement de tout process fils. En son absence * il est possible que l'exécution du process fils échoue. - * @deprecated Utiliser la version utilisant également argc et - * argv du main. + * @deprecated Utiliser la version utilisant également argc et argv du main. */ static void initialize (char* envp []); @@ -303,8 +319,7 @@ class Process * @see getCurrentSoftware * @see getCurrentSoftwareVersion */ - static void setCurrentSoftware ( - const IN_STD string& name, const Version& version = Version ("0.0.0")); + static void setCurrentSoftware (const IN_STD string& name, const Version& version = Version ("0.0.0")); /** * @return Le nom du logiciel courrant, ou une chaine vide s'il n'a pas été renseigné par setCurrentSoftware. @@ -342,20 +357,14 @@ class Process /** * @param Le message d'erreur associé à une terminaison anormale. - * Sa recopie se limite aux PROCESS_ERROR_MESSAGE_SIZE-1 - * premiers caractères. Depuis la version 4.4.0 la gestion - * du message d'erreur est géré dans un tampon pré-alloué car - * ce message peut être issu d'un signal émis et recopié - * dans un handler sur signal où il ne fait pas bon d'utiliser - * malloc et free. + * Sa recopie se limite aux PROCESS_ERROR_MESSAGE_SIZE-1 premiers caractères. Depuis la version 4.4.0 la gestion + * du message d'erreur est géré dans un tampon pré-alloué car ce message peut être issu d'un signal émis et recopié + * dans un handler sur signal où il ne fait pas bon d'utiliser malloc et free. */ -// virtual void setErrorMessage (const IN_STD string& message) // v 4.4.0 -// { _errorMessage = message; } - virtual void setErrorMessage (const char* message); // v 4.4.0 + virtual void setErrorMessage (const char* message); /** - * @return True si la terminaison du processus fils est attendue, - * sinon false. + * @return True si la terminaison du processus fils est attendue, sinon false. * @see setWaited * @see waited */ @@ -371,9 +380,7 @@ class Process { _waited = waited; } /** - * Lit les l'ensemble des données dans le pipe de communication avec - * le processus fils et les stocke dans l'attente d'appels à - * getChildLine. + * Lit les l'ensemble des données dans le pipe de communication avec le processus fils et les stocke dans l'attente d'appels à getChildLine. */ virtual void fillChildBuffer ( ); @@ -383,12 +390,11 @@ class Process * @param Si true, ajoute un caractère de fin de ligne après * la chaine. */ - virtual void appendChildBuffer ( - const IN_STD string& str, bool newLine = true); + virtual void appendChildBuffer (const IN_STD string& str, bool newLine = true); /** * Appelé lorsqu'un processus fils est fini. Marque l'instance comme terminée. - *iDepuis la version 4.4.0 ne détruit plus l'instance associée si isWaited retourne false. + * Depuis la version 4.4.0 ne détruit plus l'instance associée si isWaited retourne false. * @param nature du signal reçu. * @param informations sur l'origine du signal * @param contexte d'appel du signal @@ -417,13 +423,10 @@ class Process /** Le caractère "terminé" de l'instance. */ bool _completed; - /** Vaut true si un pipe de communication doit être ouvert de la sortie - * standard du processus fils vers le processus père. */ + /** Vaut true si un pipe de communication doit être ouvert de la sortie standard du processus fils vers le processus père. */ bool _childToSonCommunications; - /** Vaut true si les communications du processus fils vers le processus - * père sont bloquantes, false dans le cas contraire. Vaut true par - * défaut. + /** Vaut true si les communications du processus fils vers le processus père sont bloquantes, false dans le cas contraire. Vaut true par défaut. */ bool _blockingCommunications; @@ -447,8 +450,7 @@ class Process int _completionCode; /** Le message d'erreur associé à une terminaison anormale. */ -// IN_STD string _errorMessage; // v 4.4.0 - char _errorMessage [PROCESS_ERROR_MESSAGE_SIZE];// v 4.4.0 + char _errorMessage [PROCESS_ERROR_MESSAGE_SIZE]; /** La table comprenant les ids des tâches et les pointeurs sur les instances associées de cette classe. */ diff --git a/src/TkUtilScripting/CMakeLists.txt b/src/TkUtilScripting/CMakeLists.txt index 565c596..f8da659 100644 --- a/src/TkUtilScripting/CMakeLists.txt +++ b/src/TkUtilScripting/CMakeLists.txt @@ -26,6 +26,7 @@ file (GLOB CPP_SOURCES *.i *.cpp) # => dans cette version on ne génère que _TkUtilScripting qui sera utilisé directement depuis les scripts comme par les exécutables. set (ALL_TARGETS TkUtilScripting) set_property (SOURCE TkUtilScripting.i PROPERTY CPLUSPLUS ON) +set_property (SOURCE TkUtilScripting.i PROPERTY USE_SWIG_DEPENDENCIES TRUE) swig_add_library (TkUtilScripting TYPE SHARED LANGUAGE PYTHON SOURCES ${CPP_SOURCES}) cmake_policy (SET CMP0086 NEW) set_source_files_properties (TkUtilScripting.i PROPERTIES SWIG_MODULE_NAME TkUtil) @@ -39,7 +40,7 @@ if (SWIG_VERSION VERSION_GREATER 4) list (APPEND MT_SWIG_COMPILE_OPTIONS "-doxygen") endif (SWIG_VERSION VERSION_GREATER 4) # Avec cmake_policy (SET CMP0086 NEW) -module ${SWIG_MODULE_NAME} devrait être automatiquement passé, SWIG_MODULE_NAME étant défini comme propriété du fichier swig. Mais ... -swig_link_libraries (TkUtilScripting PUBLIC TkUtil ${Python_LIBRARIES}) +target_link_libraries (TkUtilScripting PUBLIC TkUtil ${Python_LIBRARIES}) target_include_directories (TkUtilScripting PUBLIC $$) foreach (lib ${ALL_TARGETS}) target_include_directories (TkUtilScripting PRIVATE ${Python_INCLUDE_DIRS}) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 50081c5..fbbad54 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -3,9 +3,9 @@ include (${GUIToolkitsVariables_CMAKE_DIR}/common.cmake) include (${GUIToolkitsVariables_CMAKE_DIR}/workarounds.cmake) set (ALL_EXECUTABLES - ansi_esc_codes canceled_threads conversions date exceptions + ansi_esc_codes canceled_threads conversions date dir_list exceptions fileExtractor fileinfos fileopts hostinfos joinable locale - logs memory modify_script remoteProcess removefile script_tags + logs memory modify_script process remoteProcess removefile script_tags scripting_logs thread_manager thread_pool timer tmpfile unicode urlfifo user_representation userinfos utf8 utf8chars ) diff --git a/src/tests/dir_list.cpp b/src/tests/dir_list.cpp new file mode 100644 index 0000000..96e2696 --- /dev/null +++ b/src/tests/dir_list.cpp @@ -0,0 +1,56 @@ +/** + * Test simple de la classe File pour avoir la composition d'un répertoire. + */ +#include "TkUtil/Exception.h" +#include "TkUtil/File.h" + +#include +#include + + +USING_STD +USING_UTIL + + + +int main (int argc, char* argv [], char* envp[]) +{ + if (2 != argc) + { + cout << "Syntax : " << argv [0] << " directory" << endl; + return -1; + } // if (2 != argc)) + + try + { + File dir (argv [1]); + vector directories, files; + dir.getChildren (directories, files); + + cout << dir.getFullFileName ( ) << "directories : " << endl; + for (vector::const_iterator itd = directories.begin ( ); directories.end ( ) != itd; itd++) + cout << (*itd).getFileName ( ) << ' '; + cout << endl; + cout << dir.getFullFileName ( ) << "files : " << endl; + for (vector::const_iterator itf = files.begin ( ); files.end ( ) != itf; itf++) + cout << (*itf).getFileName ( ) << ' '; + cout << endl; + } + catch (const Exception& exc) + { + cout << "Exception caught : " << exc.getFullMessage ( ) << endl; + return -1; + } + catch (const exception& e) + { + cout << "Standard exception caught : " << e.what ( ) << endl; + return -1; + } + catch (...) + { + cout << "Undocumented exception caught." << endl; + return -1; + } + + return 0; +} // main diff --git a/src/tests/process.cpp b/src/tests/process.cpp new file mode 100644 index 0000000..6da8517 --- /dev/null +++ b/src/tests/process.cpp @@ -0,0 +1,71 @@ +/** + * Test simple de la classe Process avec récupération de la sortie standard du processus détaché. + */ +#include "TkUtil/Exception.h" +#include "TkUtil/Process.h" + +#include +#include + + +USING_STD +USING_UTIL + + + +int main (int argc, char* argv [], char* envp[]) +{ + if (2 != argc) + { + cout << "Syntax : " << argv [0] << " directory" << endl; + return -1; + } // if (2 != argc)) + + try + { + Process::initialize (envp); + + unique_ptr process (new Process ("ls")); + process->getOptions ( ).addOption ("-al"); + process->getOptions ( ).addOption (argv [1]); + cout << "Cmd line is : " << process->getCommandLine ( ) << endl; + process->enableChildToSonCommunications (true); + process->execute (false); + const int status = process->wait ( ); + cout << "Process standard output :" << endl; + bool completed = false; + while (false == completed) + { + try + { + const string output = process->getChildLine ( ); + cout << output << endl; + } + catch (...) + { + completed = true; + } + } // while (false == completed) + if (0 != status) + cout << "Process failed : " << process->getErrorMessage ( ) << endl; + + return status; + } + catch (const Exception& exc) + { + cout << "Exception caught : " << exc.getFullMessage ( ) << endl; + return -1; + } + catch (const exception& e) + { + cout << "Standard exception caught : " << e.what ( ) << endl; + return -1; + } + catch (...) + { + cout << "Undocumented exception caught." << endl; + return -1; + } + + return 0; +} // main diff --git a/versions.txt b/versions.txt index 01e8940..d8f6a2b 100644 --- a/versions.txt +++ b/versions.txt @@ -1,3 +1,14 @@ +Version 6.10.0 : 04/10/24 +================= + +Process::wait : correctif. Retourne getCompletionCode ( ) si déjà achevé à la place de lever une exception. +Affecte des processus très brefs type "ls" dont on veut avoir un retour. Le programme test src/tests/process.cpp illustre un usage de ce type. + +Méthode File::getChildren retournant la liste des sous-répertoires et fichiers. Le programme test src/tests/dir_list.cpp illustre son usage. + +TkUtilScripting : retouches utilisation de swig (target_link_libraries, USE_SWIG_DEPENDENCIES). + + Version 6.9.0 : 06/09/24 ================